Libraries like mathjax and katex can render complex formulas on the web, without any plugins. Is there any information on how this is accomplished?
From my limited understanding of existing fonts, font shapes are essentially fixed. For example, I can increase or reduce the size of letter 'A', make it italic or bold, but there is no mechanism for arbitrarily change it's shape (for a given font).
Libraries like mathjax/katex, on the other hand, seem to do things which should not be possible for standard fonts. For example, take the square root sign. There can be a single function enclosed by the square root sign, or there can be an arbitrarily long and complex expression under it. The square root symbol adjusts accordingly. How is that possible?
One possibility is that these math 'fonts' are not fonts in the typical sense. They are just svg lines and curves as far as html is concerned. However, that doesn't seem to be the case, since I can select (parts) of an expression, the way I might select a few words in a sentence.
I am asking this because some human languages, like arabic/persian/urdu are not rendered very nicely on most web pages, and the reasons seems to be because the individual characters (or parts of characters) change according to what proceeds or follows the character. In other words, these languages need an algorithm which is context sensitive, which doesn't seem to be the case for most text rendering engines.
Curious to learn how math formulas are rendered so I can figure out how to use that technology to render Urdu (specifically nastaleeq)
You can see for yourself if you load a page containing MathJax content and examine the HTML source of the rendered elements.
It isn't pretty.
This is the HTML code generated by MathJax for the expression $\sqrt{x^2 + y^2}$
(with line breaks added by me):
<div id="wmd-preview" class="wmd-preview"><p><span class="MathJax_Preview" style="color:
inherit;"></span><span class="MathJax" id="MathJax-Element-41-Frame"><nobr><span
class="math" id="MathJax-Span-314" role="math" style="width: 4.836em; display:
inline-block;"><span style="display: inline-block; position: relative; width: 4.003em;
height: 0px; font-size: 120%;"><span style="position: absolute; clip: rect(2.947em
1000.003em 4.503em -999.997em); top: -3.997em; left: 0.003em;"><span class="mrow"
id="MathJax-Span-315"><span class="msqrt" id="MathJax-Span-316"><span style="display:
inline-block; position: relative; width: 4.003em; height: 0px;"><span style="position:
absolute; clip: rect(3.058em 1000.003em 4.392em -999.997em); top: -3.997em; left:
0.947em;"><span class="mrow" id="MathJax-Span-317"><span class="msubsup"
id="MathJax-Span-318"><span style="display: inline-block; position: relative; width:
0.947em; height: 0px;"><span style="position: absolute; clip: rect(3.392em 1000.003em
4.169em -999.997em); top: -3.997em; left: 0.003em;"><span class="mi"
id="MathJax-Span-319" style="font-family: STIXGeneral-Italic;">x<span style="display:
inline-block; overflow: hidden; height: 1px; width: 0.003em;"></span></span><span
style="display: inline-block; width: 0px; height: 4.003em;"></span></span><span
style="position: absolute; top: -4.275em; left: 0.503em;"><span class="mn"
id="MathJax-Span-320" style="font-size: 70.7%; font-family:
STIXGeneral-Regular;">2</span><span style="display: inline-block; width: 0px; height:
4.003em;"></span></span></span></span><span class="mo" id="MathJax-Span-321"
style="font-family: STIXGeneral-Regular; padding-left: 0.281em;">+</span><span
class="msubsup" id="MathJax-Span-322" style="padding-left: 0.281em;"><span
style="display: inline-block; position: relative; width: 0.892em; height: 0px;"><span
style="position: absolute; clip: rect(3.392em 1000.003em 4.392em -999.997em); top:
-3.997em; left: 0.003em;"><span class="mi" id="MathJax-Span-323" style="font-family:
STIXGeneral-Italic;">y</span><span style="display: inline-block; width: 0px; height:
4.003em;"></span></span><span style="position: absolute; top: -4.275em; left:
0.447em;"><span class="mn" id="MathJax-Span-324" style="font-size: 70.7%; font-family:
STIXGeneral-Regular;">2</span><span style="display: inline-block; width: 0px; height:
4.003em;"></span></span></span></span></span><span style="display: inline-block; width:
0px; height: 4.003em;"></span></span><span style="position: absolute; clip: rect(3.003em
1000.003em 3.392em -999.997em); top: -4.053em; left: 0.947em;"><span style="display:
inline-block; position: relative; width: 3.058em; height: 0px;"><span style="position:
absolute; font-family: STIXGeneral-Regular; top: -3.997em; left: 0.003em;">‾<span
style="display: inline-block; width: 0px; height: 4.003em;"></span></span><span
style="position: absolute; font-family: STIXGeneral-Regular; top: -3.997em; left:
2.558em;">‾<span style="display: inline-block; width: 0px; height:
4.003em;"></span></span><span style="font-family: STIXGeneral-Regular; position:
absolute; top: -3.997em; left: 0.392em;">‾<span style="display: inline-block; width:
0px; height: 4.003em;"></span></span><span style="font-family: STIXGeneral-Regular;
position: absolute; top: -3.997em; left: 0.836em;">‾<span style="display: inline-block;
width: 0px; height: 4.003em;"></span></span><span style="font-family:
STIXGeneral-Regular; position: absolute; top: -3.997em; left: 1.281em;">‾<span
style="display: inline-block; width: 0px; height: 4.003em;"></span></span><span
style="font-family: STIXGeneral-Regular; position: absolute; top: -3.997em; left:
1.725em;">‾<span style="display: inline-block; width: 0px; height:
4.003em;"></span></span><span style="font-family: STIXGeneral-Regular; position:
absolute; top: -3.997em; left: 2.114em;">‾<span style="display: inline-block; width:
0px; height: 4.003em;"></span></span></span><span style="display: inline-block; width:
0px; height: 4.003em;"></span></span><span style="position: absolute; clip: rect(2.836em
1000.003em 4.447em -999.997em); top: -3.942em; left: 0.003em;"><span style="font-family:
STIXGeneral-Regular;">√</span><span style="display: inline-block; width: 0px; height:
4.003em;"></span></span></span></span></span><span style="display: inline-block; width:
0px; height: 4.003em;"></span></span></span><span style="border-left-width: 0.003em;
border-left-style: solid; display: inline-block; overflow: hidden; width: 0px; height:
1.603em; vertical-align: -0.463em;"></span></span></nobr></span><script type="math/tex"
id="MathJax-Element-41">\sqrt{x^2 + y^2}</script></p></div>
If you look closely, you'll see several occurrences of font-family: STIXGeneral-Regular
— this is a web font that MathJax uses to produce consistent rendered output on all platforms.
If you look even closer, you'll see several overscore characters (‾
) embedded in a nest of <span>
elements. These are what MathJax uses to draw the straight line over the top of the square root.
I wouldn't look at it too closely, though. As I said, it isn't pretty. The end result looks OK though:
Fortunately, modern web browsers should have no trouble rendering context-sensitive scripts as long as they are correctly tagged (e.g., using the correct lang
and dir
attributes).