mathjax / MathJax

Beautiful and accessible math in all browsers
http://www.mathjax.org/
Apache License 2.0
10.21k stars 1.16k forks source link

Problem in displaying parentheses in formula #3206

Open saraOrkide opened 8 months ago

saraOrkide commented 8 months ago

As you can see in the photo, the last two brackets are not the same size, and it seems that it is the right way so that the last two brackets are not displayed as extended. Screenshot from 2024-03-13 10-24-18

mathjax version: 4.0.0-beta.4 using mml-chtml.js setting:

 (window.MathJax = {
            options: {
                enableMenu: !1,
            },
            loader: {
                paths: {
                    "mathjax-fira": "https://cdn.chista.me/chista-mathjax-4.0.0-beta.4/mathjax-fira-font",
                }
            },
            chtml: {
                displayAlign: 'right',
                scale: 1,
                merrorInheritFont: !0,
                matchFontHeight: false,
                mtextFont: 'fontRegular, Noto Sans, sans-serif',
                mtextInheritFont: false,
                unknownFamily: 'fontRegular, Noto Sans, sans-serif',
                font: 'mathjax-fira',
            },

            startup: {
                ready() {
                    const { ChtmlMn: e } = MathJax._.output.chtml.Wrappers.mn;
                    e.prototype.remapChars = function (t) {
                        const a = [];
                        for (const e of t) {
                            const t = this.font.getRemappedChar("mn", e);
                            a.push(...(t ? this.unicodeChars(t, this.variant) : [e]));
                        }
                        return a;
                    };
                    const { FontData: n } = MathJax._.output.common.FontData,
                        o = n.defaultMnMap;
                    for (var s = 0; s < 10; s++) o[48 + s] = String.fromCodePoint(1776 + s);
                    const { CHTML } = MathJax._.output.chtml_ts;
                    Object.assign(CHTML.prototype, {
                        _unknownText: CHTML.prototype.unknownText,
                        unknownText(text, variant, width = null, rscale = 1) {
                            const node = this._unknownText(text, variant, width, rscale);
                            if (width !== null) {
                                this.adaptor.setStyle(node, 'width', this.fixed(width * this.math.metrics.scale * rscale) + 'em');
                            }
                            return node;
                        },
                        measureTextNode(textNode) {
                            const adaptor = this.adaptor;
                            const text = adaptor.clone(textNode);
                            adaptor.setStyle(text, 'font-family', adaptor.getStyle(text, 'font-family').replace(/MJXZERO, /g, ''));
                            const em = this.math.metrics.em;
                            const style = {
                                position: 'absolute', top: 0, left: 0,
                                'white-space': 'nowrap',
                                'font-size': this.fixed(em, 3) + 'px'
                            };
                            const node = this.html('mjx-measure-text', { style }, [text]);
                            adaptor.append(adaptor.parent(this.math.start.node), this.container);
                            adaptor.append(this.container, node);
                            let w = adaptor.nodeSize(text, em)[0];
                            adaptor.remove(this.container);
                            adaptor.remove(node);

                            return { w: w, h: .85, d: .3 };
                        }
                    });
                    const { MmlMath } = MathJax._.core.MmlTree.MmlNodes.math;
                    const { MmlMstyle } = MathJax._.core.MmlTree.MmlNodes.mstyle;
                    MmlMath.defaults.scriptsizemultiplier = MmlMstyle.defaults.scriptsizemultiplier = 1;
                    MathJax.startup.defaultReady();
                    const params = MathJax.startup.document.outputJax.font.params;
                    params.rule_thickness = .130;
                    params.rule_factor = .75;
                },
            },
        });

mml code:

  <div class='chistaItem'
        style='text-align:left;justify-content:left;/*MARK-BY-CHISTA-PARSER*/;direction:ltr;/*MARK-BY-CHISTA-PARSER*/;'>
        <span class='chistaText'><span class='chistaFormula'><math>
                    <mover accent='true'>
                        <mrow>
                            <mtext>f</mtext>
                        </mrow>
                        <mo>´</mo>
                    </mover>
                    <mfenced separators='|'>
                        <mrow>
                            <mtext>x</mtext>
                        </mrow>
                    </mfenced>
                    <mo>=</mo>
                    <munder>
                        <mrow>
                            <munder accentunder='false'>
                                <mrow>
                                    <mtext>5</mtext>
                                </mrow>
                                <mo>⏟</mo>
                            </munder>
                        </mrow>
                        <mrow>
                            <mtext> توان به عنوان ضریب</mtext>
                        </mrow>
                    </munder>
                    <mtext>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</mtext>
                    <mfenced separators='|'>
                        <mrow>
                            <munder>
                                <mrow>
                                    <munder accentunder='false'>
                                        <mrow>
                                            <mtext>2x</mtext>
                                            <mo>+</mo>
                                            <mtext>2</mtext>
                                        </mrow>
                                        <mo>⏟</mo>
                                    </munder>
                                </mrow>
                                <mrow>
                                    <mtext>پایه مشتق</mtext>
                                </mrow>
                            </munder>
                        </mrow>
                    </mfenced>
                    <mtext>&nbsp;&nbsp;</mtext>
                    <mo>(</mo>
                    <msup>
                        <mrow>
                            <mtext>x</mtext>
                        </mrow>
                        <mrow>
                            <mtext>2</mtext>
                        </mrow>
                    </msup>
                    <mo>+</mo>
                    <mtext>2x</mtext>
                    <mo>+</mo>
                    <msup>
                        <mrow>
                            <mtext>1</mtext>
                            <mo>)</mo>
                            <mtext>&nbsp;</mtext>
                        </mrow>
                        <mrow>
                            <mtext>4</mtext>
                        </mrow>
                    </msup>
                </math></span></span></div>
dpvc commented 8 months ago

The MathML specification says that an mo element will stretch vertically to the size of the largest item in the mrow (explicit or implied) that contains it. The exception is when that mrow constitutes an embellished operator, in which case the mrow would contain one mo and any number of space-like elements. Space-like elements include mspace and mtext elements. The latter is included apparently because some people use mtext to include explicit space characters, as you do.

So your expression

<msup>
                        <mrow>
                            <mtext>1</mtext>
                            <mo>)</mo>
                            <mtext>&nbsp;</mtext>
                        </mrow>
                        <mrow>
                            <mtext>4</mtext>
                        </mrow>
                    </msup>

is technically an embellished operator since its base is embellished, and it should stretch to the size of the mrow that contains it, as you suggest, and it does so in v3.

Note that your <mtext>1</mtext> would normally be <mn>1</mn>, and that would make the msup no longer be an embellished operator, and so under normal circumstances, the operator would not stretch. It is only because of your unusual use of mtext that you would get the result you are looking for.

The idea that any mtext is spacelike, regardless of its content, really doesn't make sense, however, and it has many negative consequences, especially when line-breaking is in effect, as an embellished operator can't contain line breaks. You see another consequence in your expression, as the use of mtext instead of mn can have unintended consequences, as described above.

So MathJax has a modified rule for when mtext elements are spacelike, and it is only when the contents consists of actual space characters (those that match \s in a regular expression). That means, in v4, the msup is not considered an embellished operator (due to the <mtext>1</mtext> that is not spacelike), and so the core mo only stretches to the height of the 1.

Your use of msup with a base conceding of 1) is certainly peculiar, as it is not semantically correct, even though it may give the desired visual output. The 1) is not what is being raised to a power, and 1) is not what is being added to the 2x that precedes it. So the grouping of the terms is incorrect. If you move the <mtext>1</mtext> outside the msup, then the resulting msup will be an embellished operator even in MathJax v4, and will stretch to the size of the mrow that contains it, as you desire. I would also recommend removing the <mtext>&nbsp;</mtex> as that moves the superscript too far to the right.

A better solution, however, is to note that it is not the ) that is being raised to a power, but the entire parenthesized expression (x^2 + 2x + 1), so you should really have the msup around the whole thing. Of course, that will mean that neither ( nor ) will stretch to the size of the preceding ones, since they will both be inside an mrow whose height is just that of the x^2. Of course, I think the preceding parentheses shouldn't stretch either, as they really don't need to cover the underbrace and the explanation below it. One way to do that would be to replace the mfenced element (which is deprecated in MathML4) by an mrow that has explicit mo elements for the the parentheses, and add stretchy="false" to those. Alternatively you could move the mfenced element to being inside the munder for the under-brace.

I'm also wondering if the opening mover is correct, as that puts an accent onto the f, whereas I would have expected f' rather than . So I would expect

  <msup>
    <mtext>f</mtext>
    <mo>'</mo>
  </msup>

rather than

<mover accent='true'>
  <mtext>f</mtext>
  <mo>´</mo>
</mover>

(Note that your ´ (U+00B4) is not the correct character for f', which should use ' (U+0027) or (U+2032).)

Finally, <mtext>2x</mext> is semantically incorrect, as this is not a single identifier, but the product of a number and an identifier. Normally, it would be <mn>2</mn><mi>x</mi>, but since you are using mtext for everything, it should still be <mtext>2</mtex><mtext>x</mtext> to be semantically correct. Vision-impaired users who need to use screen readers will get a better experience if you use better semantic markup like this (and the same for the placement of the msup discussed above).

So an expression that incorporates these suggestions is the following:

<math xmlns="http://www.w3.org/1998/Math/MathML">
  <msup>
    <mtext>f</mtext>
    <mo>'</mo>
  </msup>
  <mfenced>
    <mtext>x</mtext>
  </mfenced>
  <mo>=</mo>
  <munder>
    <mrow>
      <munder accentunder="true">
        <mtext>5</mtext>
        <mo>⏟</mo>
      </munder>
    </mrow>
    <mtext> توان به عنوان ضریب</mtext>
  </munder>
  <mtext>&nbsp;&nbsp;&nbsp;&nbsp;</mtext>
  <mrow>
    <mo stretchy="false">(</mo>
    <munder>
      <munder accentunder="true">
        <mrow>
          <mtext>2</mtext>
          <mtext>x</mtext>
          <mo>+</mo>
          <mtext>2</mtext>
        </mrow>
        <mo>⏟</mo>
      </munder>
      <mtext>پایه مشتق</mtext>
    </munder>
    <mo stretchy="false">)</mo>
  </mrow>
  <mtext>&nbsp;&nbsp;</mtext>
  <msup>
    <mrow>
      <mo>(</mo>
      <msup>
        <mtext>x</mtext>
        <mtext>2</mtext>
      </msup>
      <mo>+</mo>
      <mtext>2</mtext>
      <mtext>x</mtext>
      <mo>+</mo>
      <mtext>1</mtext>
      <mo>)</mo>
    </mrow>
    <mtext>4</mtext>
  </msup>
</math>

which renders as:

well-rendered derivative formula

(This is without the translation of numbers to Persian, etc., as I just used a basic configuration for this example.)