foreignObject
MathML has been broken on Mozilla trunk for nearly 14 months now. I used to like running nightly builds of Firefox or SeaMonkey. But, since November 2006, my browser use has been frozen in amber.
Over the past several months, Karl Tomlinson has been toiling away fixing MathML on Mozilla trunk. And his efforts are definitely coming together. There are still a couple of rather serious layout bugs, and at least one æsthetic issue. But, with the release of the STIX fonts (you can still get a copy of the beta here), and various other improvements to the browser, I’ve been itching to get my hands on a version that had passable MathML support. Despite the remaining bugs, Firefox is good enough to begin playing around with.
One of the things I wanted to try out was the new support for SVG <foreignObject>
, which, in particular, allows one to embed MathML fragments in SVG figures. In various posts of mine, I’ve been making occasional use of the converse ability, to embed SVG in MathML equations. But the n-Category Café guys would, I think, really profit from being able to create complicated commutative diagrams, etc., in SVG.
First, install the STIX fonts, and unset the font.mathfont-family
preference that you probably set for previous versions. Now you can install the latest version.
Here’s an example, which should display correctly in Firefox3β3 and later:
It’s drawn from a blog entry by Urs, where there are quite a number of diagrams which would benefit from a similar treatment.
The markup used to create it,
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="14.75em" height="17em" viewBox="0 -4 236 268"> <desc>Pairing of states as an (n-1) functor</desc> <defs> <marker id="ttr295arrowhead" viewBox="0 0 10 10" refX="0" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="5" orient="auto"> <path d="M 0 0 L 10 5 L 0 10 z"/> </marker> </defs> <path fill="#FEE" stroke="#000" stroke-dasharray="6" d="M19,8c25,8,110,34,196,1c26,97,20,130-1,198c-86,33-171,7-196-1c-26,-97,-20,-130,1,-198"/> <g fill="none" stroke="#000" marker-end="url(#ttr295arrowhead)"> <path d="M106, 1h54"/> <path d="M68,256h54"/> <path d="M107,54c30-0.3,25,10,53,10"/> <path d="M69,196c30-0.3,25,10,53,10"/> <path d="M 58,210v33"/> <path d="M136,210v33"/> <path d="M 97,10v35"/> <path d="M176,10v35"/> <path d="M 97,68c0,54-41,36.3-41,118"/> <path d="M176,68c0,54-41,36.3-41,118"/> </g> <g font-size="14"> <foreignObject x="92" y="-10" width="16" height="20">$C$</foreignObject> <foreignObject x="172" y="-10" width="16" height="20">$C$</foreignObject> <foreignObject x="52" y="246" width="16" height="20">$C$</foreignObject> <foreignObject x="132" y="246" width="16" height="20">$C$</foreignObject> <foreignObject x="92" y="46" width="16" height="20">$V_x$</foreignObject> <foreignObject x="172" y="50" width="16" height="20">$V_y$</foreignObject> <foreignObject x="51" y="188" width="20" height="20">$V_{x'}$</foreignObject> <foreignObject x="131" y="192" width="20" height="20">$V_{y'}$</foreignObject> <foreignObject x="64" y="22" width="34" height="20">$e_1(x)$</foreignObject> <foreignObject x="132" y="26" width="16" height="24">$\Downarrow$</foreignObject> <foreignObject x="180" y="18" width="32" height="20">$e_1(y)$</foreignObject> <foreignObject x="22" y="220" width="40" height="20">$\overline{e}_2(x')$</foreignObject> <foreignObject x="90" y="224" width="16" height="20">$\Downarrow$</foreignObject> <foreignObject x="140" y="224" width="36" height="20">$\overline{e}_2(y')$</foreignObject> <foreignObject x="36" y="100" width="40" height="20">$tra(\gamma_1)$</foreignObject> <foreignObject x="128" y="72" width="52" height="24" transform="rotate(20)">$\Downarrow tra(\Sigma)$</foreignObject> <foreignObject x="150" y="128" width="40" height="20">$tra(\gamma_2)$</foreignObject> <foreignObject x="200" y="188" width="36" height="20">$X$</foreignObject> </g> </svg>
works in the comments, too. It’s kinda verbose, and so probably not all that much fun to generate. It would be great to have a more concise and intuitive pseudo-markup language to generate such things.
If you actually view source on the entry, you’ll see that the SVG that is ultimately spit out is even more (this time, unnecessarily) verbose, to keep the W3C Validator happy. I revised the SVGFix plugin for MovableType to add a <switch>
as the parent of <foreignObject>
, if one isn’t present already.
The same markup works in Instiki (which also required updating).
Here’s another example from the same post by Urs:
and the markup used to create it:
<svg xmlns="http://www.w3.org/2000/svg" width="18.75em" height="17.5em" viewBox="-30 -25 270 255"> <desc>Complicated commutative diagram, realized in SVG</desc> <defs> <marker id="svg295arrowhead" viewBox="0 0 10 10" refX="0" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="5" orient="auto"> <path d="M 0 0 L 10 5 L 0 10 z"/> </marker> <marker id="svg296arrowhead" viewBox="0 0 10 10" refX="0" refY="5" markerUnits="strokeWidth" markerWidth="6" markerHeight="4" orient="auto"> <path d="M 0 0 L 10 5 L 0 10 z"/> </marker> </defs> <g font-size="14" markdown="1"> <foreignObject x="53" y="-11" width="16" height="22">$1$</foreignObject> <foreignObject x="155" y="-11" width="16" height="22">$1$</foreignObject> <foreignObject x="53" y="192" width="16" height="22">$1$</foreignObject> <foreignObject x="155" y="192" width="16" height="22">$1$</foreignObject> <foreignObject x="220" y="90" width="16" height="22">$Id$</foreignObject> <foreignObject x="-18" y="90" width="16" height="22">$Id$</foreignObject> <foreignObject x="52" y="90" width="16" height="22">$A$</foreignObject> <foreignObject x="155" y="90" width="16" height="22">$B$</foreignObject> <foreignObject x="115" y="90" width="16" height="22">$\rho$</foreignObject> <foreignObject x="97" y="-19" width="16" height="22">$H$</foreignObject> <foreignObject x="97" y="204" width="16" height="22">$H$</foreignObject> <foreignObject x="104" y="46" width="16" height="22">$K$</foreignObject> <foreignObject x="104" y="137" width="16" height="22">$K'$</foreignObject> <foreignObject x="92" y="21" width="18" height="22">$\phi_1$</foreignObject> <foreignObject x="110" y="159" width="18" height="22">$\phi_2$</foreignObject> <foreignObject x="35" y="36" width="18" height="22">$N_A$</foreignObject> <foreignObject x="163" y="36" width="18" height="22">$N_B$</foreignObject> <foreignObject x="32" y="134" width="24" height="24">$N^\vee_A$</foreignObject> <foreignObject x="162" y="134" width="24" height="24">$N^\vee_B$</foreignObject> </g> <g fill="none" stroke="#000"> <g marker-end="url(#svg295arrowhead)"> <path d="M64.3,1H137"/> <path d="M159,11v67"/> <path d="M159,112.3v68"/> <path d="M56.3,112v68"/> <path d="M65,204.3h72"/> <path d="M56.3,11.3v67"/> <path d="M168.3,9c0,0,46,39.3,46,92.7s-36.7,85-36.7,85"/> <path d="M48,8.7c0,0-47,44.3-47,94s37.3,84,37.3,84"/> <path d="M63.3,112c0,0,16,27.3,44.7,27s39-20.6,39-20.6"/> <path d="M63.3,93.3C63.3,93.3,84,66,108,66s39,20.6,39,20.6"/> </g> <g stroke-width="2"> <path stroke-width="4" d="M43,102.7H19.3"/> <path stroke="#FFF" d="M43,102.7H19.3" marker-end="url(#svg296arrowhead)"/> <path stroke-width="4" d="M205,102.7h-22"/> <path stroke="#FFF" d="M205,102.7h-22" marker-end="url(#svg296arrowhead)"/> <path stroke-width="4" d="M146,15.5l-72,55"/> <path stroke="#FFF" d="M146,15.5l-72,55" marker-end="url(#svg296arrowhead)"/> <path stroke-width="4" d="M147,126l-72,65"/> <path stroke="#FFF" d="M147,126l-72,65" marker-end="url(#svg296arrowhead)"/> <path stroke-width="4" d="M108,75v46"/> <path stroke="#FFF" d="M108,75v46" marker-end="url(#svg296arrowhead)"/> </g> </g> </svg>
Hopefully, that’ll whet your appetite for the next release of Firefox, in which, surely, the remaining MathML rendering bugs will be fixed.
Update (2/5/2008):
One of the main advantages of using SVG is that it rescales nicely along with the text. Try changing the text zoom on this entry. Everything works nicely, except for<foreignObject>
which, as you can see, breaks horribly. Is this Firefox’s implementation? My markup? Or is, as I am beginning to suspect, the Specification flawed? On closer inspection, I think this is a Gecko bug. When you zoom the text, the scaling seems to be applied twice: once to the <foreignOject>
element and again to its <math>
child, squaring the net scale-factor. (It’s this bug.)By contrast, (now that SVG’s can be sized in em
s) rescales beautifully.
Re: foreignObject
Oddly enough, this page caused my FireFox 3b5 implementation to crash. I use XHTML+MathML+SVG, but I do not use prefix notation. This works for FireFox and Amaya. My dumb guess is that the .html extension causes Gecko to pass the page to the .html renderer, despite the server configuration of application/xhtml+xml. I thought I once read that Gecko does this because a lot of pages in the wild with the extension .html are actually tag soup despite the pplication/xhtml+xml claim. Of course, I am surely confused. The page does not crash Opera 9.5, but it cannot render the MathMl in the page.