Bad indentation at break on mspace
Issue Summary
We had an example where there was a line break on an mspace, which is fine, but it indented strangely in that spot (was way over to the left compared to the other broken lines). Here's what we were using:
and here's the output:

Is this a known bug? Is there any way to fix this?
Technical details:
MathJax Version: master - latest commit: MathJax.js v2.7.5 Client OS: Windows Browser: Chrome Version 91.0.4472.114 (Official Build) (64-bit) Renderer: HTML-CSS
Yes, it is a bug, in that the mspace line breaking doesn't take the indent attributes into account. That is because when the algorithm was first written (back in 2010 or so), the MathML spec didn't specify that the indent attributes applied to mspace. I see that they do now, but never noticed the change.
The following configuration should allow the spaces to be indented when they cause a break:
MathJax.Hub.Register.StartupHook("HTML-CSS multiline Ready", function () {
var HTMLCSS = MathJax.OutputJax["HTML-CSS"];
var MML = MathJax.ElementJax.mml;
var PENALTY = MML.mbase.prototype.HTMLlinebreakPenalty;
MML.mspace.Augment({
defaultDef: {
indentalign: MML.INDENTALIGN.AUTO,
indentshift: "0",
indenttarget: "",
indentalignfirst: MML.INDENTALIGN.INDENTALIGN,
indentshiftfirst: MML.INDENTSHIFT.INDENTSHIFT,
indentalignlast: MML.INDENTALIGN.INDENTALIGN,
indentshiftlast: MML.INDENTSHIFT.INDENTSHIFT
},
HTMLbetterBreak: function (info,state) {
if (info.values && info.values.id === this.spanID) {return false}
var values = this.getValues(
"linebreak",
"indentalign","indentshift",
"indentalignfirst","indentshiftfirst",
"indentalignlast","indentshiftlast"
);
var linebreakValue = values.linebreak;
if (!linebreakValue || this.hasDimAttr()) {
//
// The MathML spec says that the linebreak attribute should be ignored
// if any dimensional attribute is set.
//
linebreakValue = MML.LINEBREAK.AUTO;
}
//
// Get the default penalty for this location
//
var W = info.scanW, span = this.HTMLspanElement(), w = span.bbox.w;
if (span.style.paddingLeft) {w += HTMLCSS.unEm(span.style.paddingLeft)}
if (W - info.shift === 0) {return false} // don't break at zero width
var offset = HTMLCSS.linebreakWidth - W;
//
// Adjust offest for explicit first-line indent and align
//
if (state.n === 0 && (values.indentshiftfirst !== state.VALUES.indentshiftfirst ||
values.indentalignfirst !== state.VALUES.indentalignfirst)) {
var align = this.HTMLgetAlign(state,values),
shift = this.HTMLgetShift(state,values,align);
offset += (info.shift - shift);
}
//
var penalty = Math.floor(offset / HTMLCSS.linebreakWidth * 1000);
if (penalty < 0) {penalty = PENALTY.toobig - 3*penalty}
penalty += info.nest * PENALTY.nestfactor;
//
// Get the penalty for this type of break and
// use it to modify the default penalty
//
var linebreak = PENALTY[linebreakValue]||0;
if (linebreakValue === MML.LINEBREAK.AUTO && w >= PENALTY.spacelimit &&
!this.mathbackground && !this.background)
{linebreak = [(w+PENALTY.spaceoffset)*PENALTY.spacefactor]}
if (!MathJax.Object.isArray(linebreak)) {
// for breaks past the width, keep original penalty for newline
if (linebreak || offset >= 0) {penalty = linebreak * info.nest}
} else {penalty = Math.max(1,penalty + linebreak[0] * info.nest)}
//
// If the penalty is no better than the current one, return false
// Otherwise save the data for this breakpoint and return true
//
if (penalty >= info.penalty) {return false}
info.penalty = penalty; info.values = values; info.W = W; info.w = w;
values.lineleading = state.VALUES.lineleading;
values.linebreakstyle = "before"; values.id = this.spanID;
return true;
}
});
});
I know it is long and complicated, but the line breaking algorithm is complicated and arcane.
The line break occurs before the space, so the space is included in addition to the indent. That may not be what you want, but it is the easiest fix at the moment. I would have to work harder to have the space disappear, and can't take the time at the moment. If it is important, I may be able to do it later.
Thank you! That worked much better:

I do see what you mean about the space being included in the indent. All in all, though, this looks much better than before, so I'd say it's acceptable enough.