confloresa tiny technical blog.2025-11-27T00:00:00Zhttps://conflor.es/eriinterop and mathml core2025-11-27T00:00:00Zhttps://conflor.es/blog/2025-11-27-interop-and-mathml/<link rel="stylesheet" href="https://fred-wang.github.io/MathFonts/XITS/mathfonts.css">
<style>
math {
font-size: 2em;
}
.math-example {
display: flex;
justify-content: center;
align-items: center;
& > div {
display: inline-grid;
grid-template-columns: 1fr 2px 1fr;
grid-template-rows: fit-content(0);
grid-gap: var(--spacing);
& > img {
height: 100%;
width: auto;
border: none;
padding: 0.25rem;
}
@media (width < 768px) {
grid-template-columns: 1fr;
text-align: center;
justify-items: center;
& > hr {
width: 100%;
}
}
}
}
</style>
<p class="p-summary" hidden="">Interoperability makes the web better for everyone, allowing users to have a great experience regardless of their choice of browser.
We have been working on MathML Core making across browser engines as part of an agreement with the Sovereign Tech Fund.
There are some exciting developments and new features!</p>
<p><strong>Interoperability</strong> makes the web better for everyone, allowing users to have a great experience regardless of their choice of browser.
We have many standards that shape how the internet should work, drafted from <strong>consensus</strong> between different engine makers and third parties.
While having specs on how everything should function is great, we still need to <strong>align the different browser implementations</strong>.
This can be tricky as all of them have their peculiarities, and not all browsers agree on what is a priority for them.
The goal of the <a href="https://wpt.fyi/interop-2025">Interop</a> program is to select a few important features that all engines will prioritize, so users and editors can finally benefit from them.</p>
<p>A few months ago I joined <a href="https://www.igalia.com">Igalia</a>'s web platform team (and I'm really happy about it!).
Thanks to <a href="https://www.igalia.com/2025/07/14/Igalia,-Interop-and-the-Sovereign-Tech-Fund.html">an agreement</a> with the <a href="https://www.sovereign.tech/programs/fund">Sovereign Tech Fund</a>, this year we will be working on MathML and other important Interop areas.</p>
<blockquote>
<p>This post contains MathML examples. Each formula is represented twice.
Your browser renders the left one from the HTML code, while on the right there is a pre-printed SVG as a reference of how it should look.
Keep in mind that most of these features are either experimental or have just landed, so <strong>you may need the latest version of a browser to view them correctly</strong>.</p>
</blockquote>
<h2>A bit of history</h2>
<p><strong><a href="https://en.wikipedia.org/wiki/MathML">MathML</a></strong> was first published in 1998, and it grew to be a gigantic project that sought to define how mathematical notation should be rendered.
However, due to its complexity, the implementations of the browser engines were wildly different and incomplete.
This meant that editors could not rely on it, since users would see very different content depending on what they were browsing with.</p>
<pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>math</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>msubsup</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>mo</span><span class="token punctuation">></span></span>∫<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>mo</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>mn</span><span class="token punctuation">></span></span>0<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>mn</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>mn</span><span class="token punctuation">></span></span>1<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>mn</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>msubsup</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>mrow</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>msup</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>mi</span><span class="token punctuation">></span></span>x<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>mi</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>mn</span><span class="token punctuation">></span></span>2<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>mn</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>msup</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>mo</span><span class="token punctuation">></span></span>+<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>mo</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>mn</span><span class="token punctuation">></span></span>1<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>mn</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>mrow</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>math</span><span class="token punctuation">></span></span></code></pre>
<div class="math-example">
<div>
<math display="block">
<msubsup>
<mo>∫</mo>
<mn>0</mn>
<mn>1</mn>
</msubsup>
<mrow>
<msup>
<mi>x</mi>
<mn>2</mn>
</msup>
<mo>+</mo>
<mn>1</mn>
</mrow>
</math>
<hr>
<img class="no-index" alt="An integral from 0 to 1 of x squared plus one" src="https://conflor.es/images/2025/mathml-integral.svg">
</div>
</div>
<p>This is why <strong><a href="https://w3c.github.io/mathml-core">MathML Core</a></strong> was born.
It is a small subset of <a href="https://www.w3.org/TR/MathML3">MathML 3</a> that is feasible to implement in browsers.
It is based on the parts of the specification that are <strong>used in practice</strong>, adding important implementation details and testing.</p>
<p>To illustrate why this is important, Chromium had support for some parts of MathML when it was forked from WebKit.
However, it proved to be very difficult to maintain and complete, so it was removed in 2013.
My colleague Frédéric Wang led the effort to create a new implementation based on MathML Core, which was <a href="https://www.igalia.com/2023/01/10/Igalia-Brings-MathML-Back-to-Chromium.html">shipped in 2023</a>, a huge milestone for the standard.</p>
<p>We are in a very exciting moment in the MathML history, since <strong>all three major browser engines have overlapping support</strong>.
However, there is still work to be done to align the different implementations so they follow the MathML Core specification.
The goal is that one could write formulas on a website and have it look the same everywhere (like Wikipedia, which is now <a href="https://phabricator.wikimedia.org/T271001">transitioning to native MathML</a> instead of prerendered SVGs).</p>
<p>So, what have we been working on?</p>
<h2>RTL mirroring</h2>
<p>Some scripts are written from <strong>right to left</strong>, including <a href="https://en.wikipedia.org/wiki/Arabic_alphabet">Arabic</a>.
Browsers should be able to correctly render text and math in either direction, making use of the <a href="https://www.unicode.org/reports/tr9/">Unicode BiDi</a> specification and the <a href="https://learn.microsoft.com/en-us/typography/opentype/spec/features_pt#tag-rtlm"><code>rtlm</code></a> font feature.
However, the existing implementations either didn't support mirroring or had hacky behaviour that didn't work correctly for all cases. Read <a href="https://people.igalia.com/fwang/mathml-operator-mirroring-explainer.html">this explainer</a> that Frédéric made for a great visualization of the differences.</p>
<pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>link</span> <span class="token attr-name">rel</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>stylesheet<span class="token punctuation">"</span></span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>https://fred-wang.github.io/MathFonts/XITS/mathfonts.css<span class="token punctuation">"</span></span><span class="token punctuation">/></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>math</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>mrow</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>mo</span><span class="token punctuation">></span></span>{<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>mo</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>mfrac</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>mn</span><span class="token punctuation">></span></span>5<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>mn</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>mn</span><span class="token punctuation">></span></span>6<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>mn</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>mfrac</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>mo</span><span class="token punctuation">></span></span>)<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>mo</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>mrow</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>msqrt</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>mfrac</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>mn</span><span class="token punctuation">></span></span>3<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>mn</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>mn</span><span class="token punctuation">></span></span>4<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>mn</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>mfrac</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>msqrt</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>msub</span> <span class="token attr-name">displaystyle</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>true<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>mo</span><span class="token punctuation">></span></span>∲<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>mo</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>mi</span><span class="token punctuation">></span></span>C<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>mi</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>msub</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>math</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>math</span> <span class="token attr-name">dir</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>rtl<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>mrow</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>mo</span><span class="token punctuation">></span></span>{<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>mo</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>mfrac</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>mn</span><span class="token punctuation">></span></span>٥<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>mn</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>mn</span><span class="token punctuation">></span></span>٦<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>mn</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>mfrac</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>mo</span><span class="token punctuation">></span></span>)<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>mo</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>mrow</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>msqrt</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>mfrac</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>mn</span><span class="token punctuation">></span></span>٣<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>mn</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>mn</span><span class="token punctuation">></span></span>٤<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>mn</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>mfrac</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>msqrt</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>msub</span> <span class="token attr-name">displaystyle</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>true<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>mo</span><span class="token punctuation">></span></span>∲<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>mo</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>mi</span><span class="token punctuation">></span></span>ج<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>mi</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>msub</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>math</span><span class="token punctuation">></span></span></code></pre>
<div class="math-example">
<div>
<span>
<math style="font-size: 1.7rem">
<mrow>
<mo>{</mo>
<mfrac>
<mn>5</mn>
<mn>6</mn>
</mfrac>
<mo>)</mo>
</mrow>
<msqrt>
<mfrac>
<mn>3</mn>
<mn>4</mn>
</mfrac>
</msqrt>
<msub displaystyle="true">
<mo>∲</mo>
<mi>C</mi>
</msub>
</math>
<math dir="rtl" style="font-size: 1.7rem">
<mrow>
<mo>{</mo>
<mfrac>
<mn>٥</mn>
<mn>٦</mn>
</mfrac>
<mo>)</mo>
</mrow>
<msqrt>
<mfrac>
<mn>٣</mn>
<mn>٤</mn>
</mfrac>
</msqrt>
<msub displaystyle="true">
<mo>∲</mo>
<mi>ج</mi>
</msub>
</math>
</span>
<hr>
<img class="no-index" alt="A series of math formulas, first from left to right, then from right to left" src="https://conflor.es/images/2025/mathml-rtl.svg">
</div>
</div>
<p>There are two cases when it comes to mirroring. If there is a corresponding mirrored character (e.g. opening parenthesis to closing parenthesis), it is called <strong>character-level mirroring</strong> or Unicode BiDi, and the browser just needs to swap one character for the other.
Sadly, this doesn't apply to every operator.</p>
<p>Take the <em>contour clockwise integral</em>.
If we just mirror the symbol by applying a reflection symmetry about a vertical line, the arrow is suddenly pointing in the other direction, making it <em>counterclockwise</em>.
This changes the meaning of the formula!</p>
<p><img src="https://conflor.es/images/2025/mathml-integral-comparison.svg" alt="Three clockwise integrals: left to right, incorrectly mirrored (arrow pointing to the other side), and right to left" class="no-index" style="padding: 2rem; background: white"></p>
<p>To avoid this, the <code>rtlm</code> font feature can use <strong>glyph-level mirroring</strong> to provide a different set of correctly mirrored glyphs.
<em>Glyphs</em> plural since a math symbol can have different size variants to accommodate multiple contents.
Not only that, when the variants are not enough, there are glyphs for assembling arbitrarily long operators.</p>
<pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>link</span> <span class="token attr-name">rel</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>stylesheet<span class="token punctuation">"</span></span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>https://fred-wang.github.io/MathFonts/XITS/mathfonts.css<span class="token punctuation">"</span></span><span class="token punctuation">/></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>math</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>msqrt</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>mspace</span> <span class="token attr-name">height</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>0.8em<span class="token punctuation">"</span></span> <span class="token attr-name">width</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>0.8em<span class="token punctuation">"</span></span> <span class="token special-attr"><span class="token attr-name">style</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token value css language-css"><span class="token property">background</span><span class="token punctuation">:</span> tomato</span><span class="token punctuation">"</span></span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>mspace</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>msqrt</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>msqrt</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>mspace</span> <span class="token attr-name">height</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>1.5em<span class="token punctuation">"</span></span> <span class="token attr-name">width</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>0.8em<span class="token punctuation">"</span></span> <span class="token special-attr"><span class="token attr-name">style</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token value css language-css"><span class="token property">background</span><span class="token punctuation">:</span> gold</span><span class="token punctuation">"</span></span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>mspace</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>msqrt</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>msqrt</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>mspace</span> <span class="token attr-name">height</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>2.5em<span class="token punctuation">"</span></span> <span class="token attr-name">width</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>0.8em<span class="token punctuation">"</span></span> <span class="token special-attr"><span class="token attr-name">style</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token value css language-css"><span class="token property">background</span><span class="token punctuation">:</span> mediumseagreen</span><span class="token punctuation">"</span></span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>mspace</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>msqrt</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>msqrt</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>mspace</span> <span class="token attr-name">height</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>4.5em<span class="token punctuation">"</span></span> <span class="token attr-name">width</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>0.8em<span class="token punctuation">"</span></span> <span class="token special-attr"><span class="token attr-name">style</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token value css language-css"><span class="token property">background</span><span class="token punctuation">:</span> cornflowerblue</span><span class="token punctuation">"</span></span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>mspace</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>msqrt</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>math</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>math</span> <span class="token attr-name">dir</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>rtl<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>msqrt</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>mspace</span> <span class="token attr-name">height</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>0.8em<span class="token punctuation">"</span></span> <span class="token attr-name">width</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>0.8em<span class="token punctuation">"</span></span> <span class="token special-attr"><span class="token attr-name">style</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token value css language-css"><span class="token property">background</span><span class="token punctuation">:</span> tomato</span><span class="token punctuation">"</span></span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>mspace</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>msqrt</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>msqrt</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>mspace</span> <span class="token attr-name">height</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>1.5em<span class="token punctuation">"</span></span> <span class="token attr-name">width</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>0.8em<span class="token punctuation">"</span></span> <span class="token special-attr"><span class="token attr-name">style</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token value css language-css"><span class="token property">background</span><span class="token punctuation">:</span> gold</span><span class="token punctuation">"</span></span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>mspace</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>msqrt</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>msqrt</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>mspace</span> <span class="token attr-name">height</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>2.5em<span class="token punctuation">"</span></span> <span class="token attr-name">width</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>0.8em<span class="token punctuation">"</span></span> <span class="token special-attr"><span class="token attr-name">style</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token value css language-css"><span class="token property">background</span><span class="token punctuation">:</span> mediumseagreen</span><span class="token punctuation">"</span></span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>mspace</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>msqrt</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>msqrt</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>mspace</span> <span class="token attr-name">height</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>4.5em<span class="token punctuation">"</span></span> <span class="token attr-name">width</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>0.8em<span class="token punctuation">"</span></span> <span class="token special-attr"><span class="token attr-name">style</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token value css language-css"><span class="token property">background</span><span class="token punctuation">:</span> cornflowerblue</span><span class="token punctuation">"</span></span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>mspace</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>msqrt</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>math</span><span class="token punctuation">></span></span></code></pre>
<div class="math-example">
<div>
<div>
<math style="font-size: 1.3em">
<msqrt>
<mspace height="0.8em" width="0.8em" style="background: tomato"></mspace>
</msqrt>
<msqrt>
<mspace height="1.5em" width="0.8em" style="background: gold"></mspace>
</msqrt>
<msqrt>
<mspace height="2.5em" width="0.8em" style="background: mediumseagreen"></mspace>
</msqrt>
<msqrt>
<mspace height="4.5em" width="0.8em" style="background: cornflowerblue"></mspace>
</msqrt>
</math>
<math dir="rtl" style="font-size: 1.3em">
<msqrt>
<mspace height="0.8em" width="0.8em" style="background: tomato"></mspace>
</msqrt>
<msqrt>
<mspace height="1.5em" width="0.8em" style="background: gold"></mspace>
</msqrt>
<msqrt>
<mspace height="2.5em" width="0.8em" style="background: mediumseagreen"></mspace>
</msqrt>
<msqrt>
<mspace height="4.5em" width="0.8em" style="background: cornflowerblue"></mspace>
</msqrt>
</math>
</div>
<hr>
<img class="no-index" alt="A series square roots, each taller than the last. First from left to right, then from right to left" src="https://conflor.es/images/2025/mathml-roots.svg">
</div>
</div>
<p>No browser engine supported glyph-level mirroring for MathML operators, so we had to implement it in all of them.
Thankfully <a href="https://github.com/harfbuzz/harfbuzz">harfbuzz</a>, the underlying font rendering library used by Chromium and Firefox, already supported it.
WebKit is a work in progress, since there is more complexity because of different ports using different backends.
As for character-level mirroring, Chromium and WebKit did it right, but Firefox applied reflection symmetry instead of replacing the correct pair.
The changes in Firefox and Chromium are now stable and ready to be used!</p>
<div class="table-wrapper">
<table>
<thead>
<tr>
<th>Feature</th>
<th>Firefox</th>
<th>WebKit</th>
<th>Chromium</th>
</tr>
</thead>
<tbody>
<tr>
<td>Character level mirroring (BiDi)</td>
<td>✅✨</td>
<td>✅</td>
<td>✅</td>
</tr>
<tr>
<td>Glyph level mirroring (rtlm)</td>
<td>✅✨</td>
<td>🚧</td>
<td>✅✨</td>
</tr>
</tbody>
</table>
</div>
<h2><code>math-shift</code> and <code>math-depth</code></h2>
<p>Details are important, especially when rendering complex and layered formulas.
One may think that a few pixels do not make that much of a difference.
However, when you have multiple levels of nesting, offsets, and multiple elements, a slight change can make everything look ugly at best, wrong at worst.</p>
<p>Enter <code>math-shift: compact</code>. Look at this example from the <a href="https://w3c.github.io/mathml-core/#the-math-shift">MathML Core spec</a>:</p>
<pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>math</span> <span class="token attr-name">display</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>block<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>msqrt</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>msup</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>mi</span><span class="token punctuation">></span></span>x<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>mi</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>mn</span> <span class="token special-attr"><span class="token attr-name">style</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token value css language-css"><span class="token property">color</span><span class="token punctuation">:</span> mediumseagreen</span><span class="token punctuation">"</span></span></span><span class="token punctuation">></span></span>2<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>mn</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>msup</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>msqrt</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>mo</span><span class="token punctuation">></span></span>≠<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>mo</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>msup</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>mi</span><span class="token punctuation">></span></span>x<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>mi</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>mn</span> <span class="token special-attr"><span class="token attr-name">style</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token value css language-css"><span class="token property">color</span><span class="token punctuation">:</span> cornflowerblue</span><span class="token punctuation">"</span></span></span><span class="token punctuation">></span></span>2<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>mn</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>msup</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>math</span><span class="token punctuation">></span></span></code></pre>
<div class="math-example">
<div>
<math display="block">
<msqrt>
<msup>
<mi>x</mi>
<mn style="color: mediumseagreen">2</mn>
</msup>
</msqrt>
<mo>≠</mo>
<msup>
<mi>x</mi>
<mn style="color: cornflowerblue">2</mn>
</msup>
</math>
<hr>
<img class="no-index" alt="Square root of x squared does not equal x squared. The exponent under the root is lower than the exponent on the right" src="https://conflor.es/images/2025/mathml-math-shift.svg">
</div>
</div>
<p>At first glance, you may not see anything too different.
But looking closely, the green "2" on the left is a bit lower than then blue one on the right.
It is trying to <em>fit</em> under the square root bar. This is what LaTeX calls <strong>cramped mode</strong>.</p>
<p>Chromium already supported the definition given by MathML Core, so that left Firefox and WebKit, both of which used hardcoded rules for specific cases in C++ objects.
MathML Core takes another approach, and <strong>incentivizes using CSS styling rules</strong> instead.</p>
<p>Another interesting property is <a href="https://w3c.github.io/mathml-core/#the-math-script-level-property"><code>math-depth</code></a>.
It is used to make nested elements, such as those inside fractions, scripts or radicals a bit smaller.
That way, if you have an exponent of an exponent of an exponent (of an exponent...), each one is displayed a bit tinier than the last.</p>
<pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>math</span> <span class="token attr-name">display</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>block<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>msup</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>mi</span><span class="token punctuation">></span></span>A<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>mi</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>msup</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>mi</span> <span class="token special-attr"><span class="token attr-name">style</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token value css language-css"><span class="token property">color</span><span class="token punctuation">:</span> cornflowerblue</span><span class="token punctuation">"</span></span></span><span class="token punctuation">></span></span>A<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>mi</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>msup</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>mi</span> <span class="token special-attr"><span class="token attr-name">style</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token value css language-css"><span class="token property">color</span><span class="token punctuation">:</span> mediumseagreen</span><span class="token punctuation">"</span></span></span><span class="token punctuation">></span></span>A<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>mi</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>mi</span> <span class="token special-attr"><span class="token attr-name">style</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token value css language-css"><span class="token property">color</span><span class="token punctuation">:</span> tomato</span><span class="token punctuation">"</span></span></span><span class="token punctuation">></span></span>A<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>mi</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>msup</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>msup</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>msup</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>mo</span><span class="token punctuation">></span></span>+<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>mo</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>mroot</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>mi</span><span class="token punctuation">></span></span>A<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>mi</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>mi</span> <span class="token special-attr"><span class="token attr-name">style</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token value css language-css"><span class="token property">color</span><span class="token punctuation">:</span> mediumseagreen</span><span class="token punctuation">"</span></span></span><span class="token punctuation">></span></span>A<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>mi</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>mroot</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>mo</span><span class="token punctuation">></span></span>+<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>mo</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>mfrac</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>mrow</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>mi</span><span class="token punctuation">></span></span>A<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>mi</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>mo</span><span class="token punctuation">></span></span>+<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>mo</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>mfrac</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>mi</span> <span class="token special-attr"><span class="token attr-name">style</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token value css language-css"><span class="token property">color</span><span class="token punctuation">:</span> cornflowerblue</span><span class="token punctuation">"</span></span></span><span class="token punctuation">></span></span>A<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>mi</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>mi</span> <span class="token special-attr"><span class="token attr-name">style</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token value css language-css"><span class="token property">color</span><span class="token punctuation">:</span> cornflowerblue</span><span class="token punctuation">"</span></span></span><span class="token punctuation">></span></span>A<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>mi</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>mfrac</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>mrow</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>mi</span><span class="token punctuation">></span></span>A<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>mi</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>mfrac</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>math</span><span class="token punctuation">></span></span></code></pre>
<div class="math-example">
<div>
<math display="block">
<msup>
<mi>A</mi>
<msup>
<mi style="color: cornflowerblue">A</mi>
<msup>
<mi style="color: mediumseagreen">A</mi>
<mi style="color: tomato">A</mi>
</msup>
</msup>
</msup>
<mo>+</mo>
<mroot>
<mi>A</mi>
<mi style="color: mediumseagreen">A</mi>
</mroot>
<mo>+</mo>
<mfrac>
<mrow>
<mi>A</mi>
<mo>+</mo>
<mfrac>
<mi style="color: cornflowerblue">A</mi>
<mi style="color: cornflowerblue">A</mi>
</mfrac>
</mrow>
<mi>A</mi>
</mfrac>
</math>
<hr>
<img class="no-index" alt="A variable with nested exponents, each smaller than the last. A radical with index A, smaller than the value inside the root. A nested fraction, whose variables are also displayed smaller." src="https://conflor.es/images/2025/mathml-math-depth.svg">
</div>
</div>
<p>In this case, Firefox and Chromium already had compliant implementations, so only WebKit needed to catch up.
Support for <code>math-depth</code> and the <a href="https://w3c.github.io/mathml-core/#dfn-scriptlevel"><code>scriptlevel</code></a> attribute (which allows to modify this depth) has now landed,
while a patch for <a href="https://www.w3.org/TR/css-fonts-4/#valdef-font-size-math"><code>font-size: math</code></a> (which sets the size of the element based on its depth) is on the way.</p>
<div class="table-wrapper">
<table>
<thead>
<tr>
<th>Feature</th>
<th>Firefox</th>
<th>WebKit</th>
<th>Chromium</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>math-shift: compact</code></td>
<td>✅✨</td>
<td>✅✨</td>
<td>✅</td>
</tr>
<tr>
<td><code>math-depth</code></td>
<td>✅</td>
<td>✅✨</td>
<td>✅</td>
</tr>
<tr>
<td><code>font-size: math</code></td>
<td>✅</td>
<td>🚧</td>
<td>✅</td>
</tr>
<tr>
<td><code>scriptlevel</code></td>
<td>✅</td>
<td>✅✨</td>
<td>✅</td>
</tr>
</tbody>
</table>
</div>
<h2 style="margin: var(--spacing) 0">Other work</h2>
<h3>Rendering unknown elements as mrow</h3>
<p>MathML 3 defined 195 elements.
MathML Core focuses on about <strong>30</strong>, leaving the rest to styling or polyfills.
This means deprecating some features that were previously implemented in some browsers, like <code>mfenced</code>, <code>semantics</code>, and <code>maction</code>, as it would be too difficult to make them interoperable right now.
To prevent breaking existing content too much, they are rendered like an <code>mrow</code>.</p>
<h3><code>font-family: math</code></h3>
<p>Selecting a <strong>good math font</strong> is essential for rendering.
Stretchy operators, math symbols, and italics are not available with every font, so without one they are presented very poorly.
<a href="https://drafts.csswg.org/css-fonts/#math-def"><code>font-family: math</code></a> is a CSS property that specifies that the content should use a suitable font for mathematics.
Previously browsers had a hardcoded list of CSS fallbacks, but now this has been standardized and implemented.</p>
<p>Android doesn't come with a math font installed, so it mixes symbols from different fonts, producing a rather unappealing result:</p>
<p><img src="https://conflor.es/images/2025/mathml-poor-rendering.webp" alt="A math formula containing different symbols, all of them with varying font styling and weights as the result of not having an unified math font family" class="no-index"></p>
<h3><code>mathvariant</code> and <code>text-transform: math-auto</code></h3>
<p>Single letter identifiers inside a <code><mi></code> tag are treated as variables, and so they should be rendered with <strong><em>fancy italics</em></strong>.
This is still supported by MathML Core.
However, MathML 3 allows a plethora of transformations using <code>mathvariant</code>, from bold to gothic text.
The new spec says that while italic transformation should still happen by default, other text should <strong>use the specific Unicode codepoint directly</strong>, as it just adds too much complexity for the browser implementation.</p>
<p><code>text-transform: math-auto</code> is a CSS property applied by default to <code><mi></code> elements that enables the italic transformation for them.
Setting the new <code>mathvariant</code> attribute to <code>normal</code> will make the <code>text-transform</code> of the element be <code>none</code>, removing the italic styling.</p>
<p><img src="https://conflor.es/images/2025/mathml-mathvariant.svg" alt="Different stylings of the letter A. Italic, regular, bold italic, bold regular, double struck, script, fraktur, sans serif and monospace" class="no-index" style="padding: 2rem; background: white"></p>
<h3><code>DisplayOperatorMinHeight</code> and Cambria Math</h3>
<p>Microsoft <a href="https://github.com/MicrosoftDocs/typography-issues/issues/1136">made a mistake</a> in Cambria Math, one of the math fonts used in Windows.
They switched the <code>DisplayOperatorMinHeight</code> and <code>DelimitedSubFormulaMinHeight</code>, so operators <a href="https://github.com/w3c/mathml-core/issues/126">weren't being displayed correctly</a>.
Some browsers had a workaround for this, but a more general fix was implemented in harfbuzz, so we removed the workarounds in favour of relying on the upstream library instead.</p>
<h3>Animation for <code>math-*</code> properties</h3>
<p>When implementing <code>math-shift</code> in Firefox, we noticed that the spec said the new properties are not supposed to be animatable.
In the new CSS spec, most properties are defined as animatable (<em>fun!</em>).
After some discussion with the MathML Working Group, we decided to change the spec, and we are adding this feature to the browser engines.</p>
<style>
@keyframes math-anim {
0% { color: royalblue; math-depth: 1; }
20% { color: mediumseagreen; }
40% { color: gold; }
60% { color: tomato; math-depth: 3; }
80% { color: mediumpurple; }
100% { color: royalblue; math-depth: 1; }
}
#anim-target {
animation: math-anim 5s infinite;
}
#anim-container {
height: 4.5rem;
& > math {
font-size: 4rem;
}
}
</style>
<p id="anim-container">
<math display="block">
<msup>
<mi>x</mi>
<mo id="anim-target">2</mo>
</msup>
</math>
</p>
<div class="table-wrapper">
<table>
<thead>
<tr>
<th>Feature</th>
<th>Firefox</th>
<th>WebKit</th>
<th>Chromium</th>
</tr>
</thead>
<tbody>
<tr>
<td>Render unknown elements as <code>mrow</code></td>
<td>✅✨</td>
<td>✅✨</td>
<td>✅</td>
</tr>
<tr>
<td><code>font-family: math</code></td>
<td>✅✨</td>
<td>✅✨</td>
<td>✅</td>
</tr>
<tr>
<td><code>text-transform: math-auto</code></td>
<td>✅</td>
<td>✅✨</td>
<td>✅</td>
</tr>
<tr>
<td>New <code>mathvariant</code> behaviour</td>
<td>✅</td>
<td>🚧</td>
<td>✅</td>
</tr>
<tr>
<td><code>DisplayOperatorMinHeight</code> fix</td>
<td>✅✨</td>
<td>✅✨</td>
<td>✅✨</td>
</tr>
<tr>
<td>Animation for <code>math-*</code> properties</td>
<td>✅✨</td>
<td>🚧</td>
<td>🚧</td>
</tr>
</tbody>
</table>
</div>
<h2>What's next?</h2>
<p>Many of these improvements have already shipped, but our work continues on making mathematics more interoperable in browsers.
This includes some <em>exciting</em> new features ahead:</p>
<ul>
<li><strong>Updates to the operator dictionary:</strong>
MathML Core revamped the existing list of operators and their default layouts.
Additionally, there is a new compact form that removes redundancies.</li>
<li><strong>More improvements to operator stretching and spacing:</strong>
There are still some inconsistencies between browsers and some long standing bugs that we would love to tackle.</li>
<li><strong>Handling positioned elements and forbidding floats in MathML:</strong>
Like flex or grid, MathML doesn't create floating children for elements with a <code>math</code> display type.
However, they can still have out of flow positioned children.
At the moment this isn't consistent across browsers and it is something we want to improve.</li>
</ul>
<p>Working on MathML is very rewarding, specially because of the people that have helped along the way.
I'd like to specially thank my colleague <a href="https://github.com/fred-wang">@fredw</a>, reviewers from Mozilla, Apple and Google, and the <a href="https://www.w3.org/groups/wg/math/">W3C Math Working Group</a>.
Also <a href="https://github.com/delan">@delan</a> for reviewing the first draft of this post.</p>
<p>We are very grateful to the Sovereign Tech Fund for supporting this work!</p>
reviving the devtools support in servo2024-09-20T00:00:00Zhttps://conflor.es/blog/2024-09-20-reviving-devtools-in-servo/<p>This blog post was written for the <a href="https://servo.org/blog/2024/09/20/devtools">Servo blog</a> in collaboration with <a href="https://github.com/delan">@delan</a> and <a href="https://github.com/mrobinson">@mrobinson</a>.
It highlights improvements made to the devtools support, including inspecting the DOM tree, viewing styles, evaluating JavaScript, and reading console messages.</p>
<hr>
<p class="p-summary">Servo has been working on improving our <a href="https://firefox-source-docs.mozilla.org/devtools-user">Firefox devtools</a> support as part of the <a href="https://www.outreachy.org">Outreachy</a> internship program since June, and we're thrilled to share significant progress.</p>
<p><img src="https://conflor.es/images/2024/devtools-inspector.png" alt="The HTML and CSS inspector is able to display the DOM elements and their attributes and CSS properties."></p>
<p>Devtools are a set of <strong>browser web developer tools</strong> that allows you to examine, edit, and debug HTML, CSS, and JavaScript.
Servo leverages existing work from the Firefox devtools to inspect its own websites, employing the same open protocol that is used for connecting to other Firefox instances.</p>
<p>While relying on a third party API allows us to offer this functionality without building it from scratch, it doesn't come without downsides.
Back in June last year, with the release of Firefox 110, changes to the protocol <strong>broke our previous implementation</strong>.
The core issue was that the message structure sent between Servo and Firefox for the devtools functionality had changed.</p>
<p>To address this, we first updated an existing patch to fix the connection and list the webviews running in Servo (<a href="https://github.com/fabricedesre">@fabricedesre</a>, <a href="https://github.com/eerii">@eerii</a>, <a href="https://github.com/mrobinson">@mrobinson</a>, <a href="https://github.com/servo/servo/pull/32475">#32475</a>).
We also had to update the structure of some <a href="https://firefox-source-docs.mozilla.org/devtools/backend/actor-hierarchy.html">actors</a> (pieces of code that respond to messages sent by Firefox with relevant information), since they changed significantly (<a href="https://github.com/eerii">@eerii</a>, <a href="https://github.com/servo/servo/pull/32509">#32509</a>).</p>
<p>One of the main challenges was figuring out the messages we needed to send back to Firefox.
The <a href="https://searchfox.org/mozilla-central/source/devtools/server/actors">source code</a> for their devtools implementation is very well commented and proved to be invaluable.
However, it was also helpful to see the actual messages being sent.
While Servo can show the ones it sends and receives, <strong>debugging another instance of Firefox</strong> to observe its messages was very useful.
To facilitate this, we made a helper script (<a href="https://github.com/eerii">@eerii</a>, <a href="https://github.com/servo/servo/pull/32684">#32684</a>) using <a href="https://www.wireshark.org">Wireshark</a> to inspect the connection between the devtools client and server, allowing us to view the contents of each packet and search through them.</p>
<p><strong>Support for the console</strong> was fixed, enabling the execution of JavaScript code directly in Servo's webviews and displaying any warnings or errors that the page emits (<a href="https://github.com/eerii">@eerii</a>, <a href="https://github.com/mrobinson">@mrobinson</a>, <a href="https://github.com/servo/servo/pull/32727">#32727</a>).</p>
<p><img src="https://conflor.es/images/2024/devtools-console.png" alt="The JavaScript developer console now displays page logs. It can also run commands."></p>
<p>Finally, the most significant changes involved the <strong>DOM inspector</strong>.
Tighter integration with Servo's script module was required to retrieve the properties of each element.
Viewing CSS styles was particularly challenging, since they can come from many places, including the <code>style</code> attribute, a stylesheet, or from ancestors, but <a href="https://github.com/emilio">@emilio</a> had great insight into where to look.
As a result, it’s now possible to view the HTML tree, and add, remove, or modify any attribute or CSS property (<a href="https://github.com/eerii">@eerii</a>, <a href="https://github.com/mrobinson">@mrobinson</a>, <a href="https://github.com/servo/servo/pull/32655">#32655</a>, <a href="https://github.com/servo/servo/pull/32884">#32884</a>, <a href="https://github.com/servo/servo/pull/32888">#32888</a>, <a href="https://github.com/servo/servo/pull/33025">#33025</a>).</p>
<p>There is still work to be done.
Some valuable features like the Network and Storage tabs are still not functional, and parts of the DOM inspector are still barebones.
For example, now that flexbox is enabled by default (<a href="https://github.com/mrobinson">@mrobinson</a>, <a href="https://github.com/servo/servo/pull/33186">#33186</a>), it would be a good idea to support it in the Layout panel.
We’re working on <strong>developer documentation</strong> that will be available in the <a href="https://book.servo.org">Servo book</a> to make future contributions easier.</p>
<p>That said, the <strong>Console</strong> and <strong>Inspector</strong> support has largely landed, and you can enable them with the <code>--devtools</code> flag in servoshell.
For a step-by-step guide on how to use Servo’s devtools, check out the new <a href="https://book.servo.org/hacking/using-devtools.html">devtools chapter</a> in the Servo book.
We'd love to hear your feedback on how these work and what additional features you'd find helpful in your workflow.</p>
<p>Many thanks to Outreachy for the internship that made this possible!</p>
(w)hat is the (p)oint of (t)hese?2024-06-18T00:00:00Zhttps://conflor.es/blog/2024-06-18-wpt-tests/<p>One of the first things I saw when contributing to Servo were the pull request <a href="https://github.com/servo/servo/blob/main/CONTRIBUTING.md">guidelines</a>. They mentioned the importance of <strong>WPT</strong> tests when adding or changing features. I knew why tests were important, but I was left wondering what WPT was. Since what I was doing was some light refactoring and it didn’t require new tests, I didn't give it more thought at the time.</p>
<p>Nearing the end of the contribution period I decided to tackle an issue with how videos were displayed. There are many ways the user can specify a video’s size: both width or height, one of them, or even none. <em>What if the video itself has a predefined size?</em> At the moment, Servo only handled one very simple case, so there was room for improvement.</p>
<p>At first I imagined I would have to check all different options and write tests for them. But to my surprise, the original issue linked to a file: <a href="https://github.com/servo/servo/blob/main/tests/wpt/tests/html/semantics/embedded-content/the-video-element/intrinsic_sizes.htm"><code>intrinsic_sizes.htm</code></a>. <em>What was this mysterious file?</em> It was located inside the <code>tests</code> folder, which I had not touched before. And more than that, it was in the <code>tests/wpt</code> folder! I couldn’t go any longer without knowing what those letters meant, so I turned to a web search.</p>
<h2>Web Platform Tests</h2>
<p>That actually makes sense. Looking at the first result, <a href="https://web-platform-tests.org">web-platform-tests.org</a>:</p>
<blockquote>
<p>The web-platform-tests project is a <strong>cross-browser test suite</strong> for the Web-platform stack. Writing tests in a way that allows them to be run in all browsers gives browser projects confidence that they are shipping software which is compatible with other implementations, and that later implementations will be compatible with their implementations. This in turn gives Web authors/developers confidence that they can actually rely on the Web platform to deliver on the promise of <em>working across browsers and devices</em> without needing extra layers of abstraction to paper over the gaps left by specification editors and implementors.</p>
</blockquote>
<p>Looking inside the <code>tests/wpt</code> directory, there were more than 120.000 files! All of them testing one specific feature to make sure it was consistent.</p>
<h3>What they actually are</h3>
<p>Let's take the test that I was trying to fix as an example, <code>intrinsic_sizes.htm</code>. This was an HTML file that declared some of the multiple options we talked about before, with a script tag that tested each case. You can actually open this with another browser and see the expected result. You can even go <a href="https://wpt.live/html/semantics/embedded-content/the-video-element/intrinsic_sizes.htm">here</a> and see the full test suite online!</p>
<pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>video</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>v1<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>video</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>video</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>v2<span class="token punctuation">"</span></span> <span class="token attr-name">width</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>400<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>video</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>video</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>v3<span class="token punctuation">"</span></span> <span class="token attr-name">height</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>100<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>video</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>video</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>v4<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>video</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>video</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>v5<span class="token punctuation">"</span></span> <span class="token attr-name">poster</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>/media/poster.png<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>video</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>script</span><span class="token punctuation">></span></span><span class="token script"><span class="token language-javascript">
<span class="token operator">...</span>
</span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>script</span><span class="token punctuation">></span></span></code></pre>
<h3>Why are they helpful</h3>
<p>When adding the expected behaviour, it was very useful having this tests that not only told you if the result was right, but where you could see visually what was happening in the page. When they all finally listed the big <strong>OK</strong> in green, it felt really good!</p>
<p>Last week I was very lucky to attend a <a href="https://www.w3.org/groups/wg/css/participants/">CSS Working Group</a> panel, which was an amazing experience. It gave me much insight into how web standards are written and the people behind them are so cool! But what striked me the most was that probably the phrase they mentioned the most was: "web platform tests". They really insisted on the importance of adding WPTs to be able to test the functionality that the standard proposed and that it works the same across browsers, which can be tricky. And they are specially useful for projects like Servo, which are implementing all of this web browser features from scratch.</p>
<h2>What I have been working on</h2>
<p>These past two weeks I have been working on reimplementing the web inspector feature in Servo. This works by sending JSON messages between Servo and the Firefox DevTools client. Since this API is internal to Firefox and it is not througly documented, most of the work went into reversing engineering what was happening. I went through some fun adventures, like debugging the Firefox Android browser, trying to listen to the messages in between using tools like Wireshark, putting breakpoints in the browser itself and using some cool third party projects like <a href="https://github.com/jpramosi/geckordp">geckordp</a>.</p>
<p>Despite you can't see any difference when you click the "Inspect" button in a Servo tab, it is getting there. Now we have a Watcher actor that lists the debugging capabilities and sends DevTools a list of targets and resources that it can inspect. There are a few messages left to send, but I think that we will be able to start seeing things on the screen, like Servo's console or the webpage source code. It is always very rewarding when you finally can watch your work take shape into something specific.</p>
<p>I hope that you could learn something from this blog post, like I did when researching what WPT was. My main takeaways are that testing is <strong>very</strong> important, and that you should always be willing to investigate new things.</p>
<p>See you next week!</p>