Skip to content

Commit 2e5c45b

Browse files
authored
Merge pull request #1173 from mathjax/chtml-stretchies
Remove use of css transforms for handling strechy assemblies in CHTML output
2 parents 3853e66 + 7b63129 commit 2e5c45b

4 files changed

Lines changed: 189 additions & 68 deletions

File tree

ts/output/chtml.ts

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -100,12 +100,20 @@ export class CHTML<N, T, D> extends CommonOutputJax<
100100
//
101101
// Clip the token elements' character content,
102102
// to remove excessive height and depth of ZERO font
103+
// Do the same for stretchy characters
103104
//
104-
'mjx-mo > mjx-c, mjx-mi > mjx-c, mjx-mn > mjx-c, mjx-ms > mjx-c, mjx-mtext > mjx-c':
105-
{
106-
'clip-path':
107-
'padding-box xywh(-1em -2px calc(100% + 2em) calc(100% + 4px))',
108-
},
105+
[[
106+
'mjx-mo > mjx-c',
107+
'mjx-mi > mjx-c',
108+
'mjx-mn > mjx-c',
109+
'mjx-ms > mjx-c',
110+
'mjx-mtext > mjx-c',
111+
'mjx-stretchy-h',
112+
'mjx-stretchy-v',
113+
].join(', ')]: {
114+
'clip-path':
115+
'padding-box xywh(-1em -2px calc(100% + 2em) calc(100% + 4px))',
116+
},
109117

110118
'mjx-container[jax="CHTML"] :focus': { outline: 'solid 2px' },
111119
'mjx-container [space="1"]': { 'margin-left': '.111em' },

ts/output/chtml/FontData.ts

Lines changed: 52 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -445,16 +445,15 @@ export class ChtmlFontData extends FontData<
445445
const m = this.em(Hm / 2 - 0.03);
446446
styles[`mjx-stretchy-v${c} > mjx-ext:first-of-type`] = {
447447
height: '50%',
448-
'border-width': `${this.em0(Hb - 0.03)} 0 ${m}`,
448+
'border-width': `${this.em1(Hb - 0.03)} 0 ${m}`,
449449
};
450450
styles[`mjx-stretchy-v${c} > mjx-ext:last-of-type`] = {
451451
height: '50%',
452-
'border-width': `${m} 0 ${this.em0(He - 0.03)}`,
452+
'border-width': `${m} 0 ${this.em1(He - 0.03)}`,
453453
};
454454
} else if (He || Hb) {
455-
styles['mjx-stretchy-v' + c + ' > mjx-ext'] = {
456-
'border-width': `${this.em0(Hb - 0.03)} 0 ${this.em0(He - 0.03)}`,
457-
};
455+
styles[`mjx-stretchy-v${c} > mjx-ext`]['border-width'] =
456+
`${this.em1(Hb - 0.03)} 0 ${this.em1(He - 0.03)}`;
458457
}
459458
}
460459

@@ -483,28 +482,25 @@ export class ChtmlFontData extends FontData<
483482
// If the non-extender is wider than the assembly,
484483
// use negative margins to center over the assembly
485484
//
486-
if (w > HDW[2]) {
487-
css.margin = `0 ${this.em((HDW[2] - w) / 2)}`;
488-
}
485+
const dw = w > HDW[2] ? this.em((HDW[2] - w) / 2) : 'auto';
489486
//
490487
// Non-extenders are 0 height, so place properly
491488
//
492489
const y = part === 'beg' ? h : part === 'end' ? -d : (h - d) / 2;
493-
if (y > 0) {
494-
css['padding-top'] = this.em(y);
495-
} else if (y < 0) {
496-
css.transform = `translateY(${this.em(y)})`;
497-
}
490+
css.margin = `${this.em(y)} ${dw} ${this.em(-y)}`;
498491
} else {
499492
//
500-
// Put one fifth above the top of the extender (to avoid ragged ends)
501-
// and then scale with origin at the top of the extender (so most extends down)
493+
// Set the line-height to have the extenders touch,
494+
// (plus a little extra for Safari, whose line-height is
495+
// not accurate), and shift the extender stack to overlap
496+
// the ends.
502497
//
503-
const y = h - (h + d) / 5;
504-
css.transform = `translateY(${this.em(y)}) scaleY(500)`;
505-
css['transform-origin'] = `center ${this.em(0.03 - y)}`;
498+
css['line-height'] = this.em0(h + d + .005);
499+
styles[`mjx-stretchy-v${c} > mjx-${part} > mjx-spacer`] = {
500+
'margin-top': this.em(-d),
501+
};
506502
}
507-
styles[`mjx-stretchy-v${c} mjx-${part} mjx-c`] = css;
503+
styles[`mjx-stretchy-v${c} > mjx-${part}`] = css;
508504
return h + d;
509505
}
510506

@@ -551,9 +547,12 @@ export class ChtmlFontData extends FontData<
551547
'border-width': `0 ${this.em0(We - 0.03)} 0 ${m}`,
552548
};
553549
} else if (Wb || We) {
554-
styles[`mjx-stretchy-h${c} > mjx-ext`] = {
555-
'border-width': `0 ${this.em0(We - 0.03)} 0 ${this.em0(Wb - 0.03)}`,
556-
};
550+
styles[`mjx-stretchy-h${c} > mjx-ext`]['border-width'] =
551+
`0 ${this.em0(We - 0.06)} 0 ${this.em0(Wb - 0.06)}`;
552+
}
553+
if (data.ext) {
554+
styles[`mjx-stretchy-h${c} > mjx-ext > mjx-spacer`]['letter-spacing'] =
555+
this.em(-data.ext);
557556
}
558557
}
559558

@@ -575,17 +574,32 @@ export class ChtmlFontData extends FontData<
575574
HDW: ChtmlCharData
576575
): number {
577576
if (!n) return 0;
578-
const [, , w, options] = this.getChar(v, n);
577+
let [, , w, options] = this.getChar(v, n);
579578
const css: StyleData = {
580579
padding: this.padding(HDW as ChtmlCharData, w - HDW[2]),
581580
};
582-
if (part === 'end') {
583-
css['margin-left'] = this.em(-w);
584-
} else if (part === 'mid') {
585-
css['margin-left'] = this.em(-w / 2);
581+
if (part === 'ext') {
582+
if (!w && options.dx) {
583+
w = 2 * options.dx - 0.06;
584+
}
585+
styles[`mjx-stretchy-h${c} > mjx-${part} > mjx-spacer`] = {
586+
'margin-left': this.em(-w / 2),
587+
};
588+
if (options.cmb) {
589+
styles[`mjx-stretchy-h${c} > mjx-${part} > mjx-c`] = {
590+
width: this.em(w),
591+
'text-align': 'right',
592+
};
593+
}
594+
} else {
595+
if (part === 'mid') {
596+
css['margin'] = `0 ${this.em(-w / 2)}`;
597+
} else {
598+
css[part == 'end' ? 'margin-left' : 'margin-right'] = this.em(-w);
599+
}
600+
this.checkCombiningChar(options, css);
586601
}
587-
this.checkCombiningChar(options, css);
588-
styles[`mjx-stretchy-h${c} mjx-${part} mjx-c`] = css;
602+
styles[`mjx-stretchy-h${c} > mjx-${part}`] = css;
589603
return w;
590604
}
591605

@@ -653,6 +667,15 @@ export class ChtmlFontData extends FontData<
653667
return em(Math.max(0, n));
654668
}
655669

670+
/**
671+
* @param {number} n The number of ems (will be restricted to non-negative values, with .1px rather than 0em)
672+
* @returns {string} The string representing the number with units of "em"
673+
*/
674+
public em1(n: number): string {
675+
const m = em(Math.max(0, n));
676+
return m === '0' ? '.1px' : m;
677+
}
678+
656679
/**
657680
* @param {ChtmlCharData} data The [h, d, w] data for the character
658681
* @param {number} ic The (optional) italic correction value

0 commit comments

Comments
 (0)