Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 18 additions & 9 deletions ts/output/chtml/FontData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import {
StyleJsonSheet,
} from '../../util/StyleJson.js';
import { em } from '../../util/lengths.js';
import { VFUZZ, HFUZZ } from '../common/FontData.js';

export * from '../common/FontData.js';

Expand Down Expand Up @@ -479,6 +480,7 @@ export class ChtmlFontData extends FontData<
HDW: ChtmlCharData
): number {
if (!n) return 0;
let fuzz = 0;
const [h, d, w] = this.getChar(v, n);
const css: StyleJsonData = { width: this.em0(w) };
if (part !== 'ext') {
Expand All @@ -494,18 +496,25 @@ export class ChtmlFontData extends FontData<
css.margin = `${this.em(y)} ${dw} ${this.em(-y)}`;
} else {
//
// Adjust the height and depth for a little overlap.
// Set the line-height to have the extenders touch,
// (plus a little extra for Safari, whose line-height is
// not accurate), and shift the extender stack to overlap
// the ends.
// and shift the extender stack to overlap the ends.
//
css['line-height'] = this.em0(h + d + 0.005);
styles[`mjx-stretchy-v${c} > mjx-${part} > mjx-spacer`] = {
'margin-top': this.em(-d),
};
fuzz = VFUZZ;
const lh = Math.max(VFUZZ, h + d - VFUZZ);
css['line-height'] = this.em0(lh);
//
// Adjust the top margin to make sure we have overlap with the top part
//
const D = h - lh / 2 - VFUZZ;
if (D) {
styles[`mjx-stretchy-v${c} > mjx-ext > mjx-spacer`] = {
'margin-top': this.em(D),
};
}
}
styles[`mjx-stretchy-v${c} > mjx-${part}`] = css;
return h + d;
return Math.max(0, h + d - fuzz);
}

/*******************************************************/
Expand Down Expand Up @@ -556,7 +565,7 @@ export class ChtmlFontData extends FontData<
}
if (data.ext) {
styles[`mjx-stretchy-h${c} > mjx-ext > mjx-spacer`]['letter-spacing'] =
this.em(-data.ext);
this.em(-data.ext - HFUZZ);
}
}

Expand Down
36 changes: 30 additions & 6 deletions ts/output/chtml/Wrappers/mo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ import {
ChtmlDelimiterData,
ChtmlFontData,
ChtmlFontDataClass,
VFUZZ,
HFUZZ,
} from '../FontData.js';
import { CharDataArray } from '../../common/FontData.js';
import {
Expand Down Expand Up @@ -273,7 +275,7 @@ export const ChtmlMo = (function <N, T, D>(): ChtmlMoClass<N, T, D> {
// The ext parameter should be 0, but line-height in Safari
// is not accurate, so this produces extra extenders to compensate
//
this.createAssembly(parts, stretch, stretchv, dom, h + d, 0.05, '\n');
this.createAssembly(parts, stretch, stretchv, dom, h + d, VFUZZ, '\n');
//
// Vertical needs an extra (empty) element to get vertical position right
// in some browsers (e.g., Safari)
Expand All @@ -282,7 +284,8 @@ export const ChtmlMo = (function <N, T, D>(): ChtmlMoClass<N, T, D> {
styles.height = this.em(h + d);
styles.verticalAlign = this.em(-d);
} else {
this.createAssembly(parts, stretch, stretchv, dom, w, delim.ext || 0);
const ext = (delim.ext || 0) + HFUZZ;
this.createAssembly(parts, stretch, stretchv, dom, w, ext);
styles.width = this.em(w);
}
//
Expand Down Expand Up @@ -340,10 +343,12 @@ export const ChtmlMo = (function <N, T, D>(): ChtmlMoClass<N, T, D> {
// Set up the beginning, extension, and end pieces
//
this.createPart('mjx-beg', parts[0], sn[0], sv[0], dom);
this.createPart('mjx-ext', parts[1], sn[1], sv[1], dom, WH1, WHx, nl);
/* prettier-ignore */
this.createPart('mjx-ext', parts[1], sn[1], sv[1], dom, WH1, WHx, nl, WHb, WHm / 2 || WHe);
if (parts[3]) {
this.createPart('mjx-mid', parts[3], sn[3], sv[3], dom);
this.createPart('mjx-ext', parts[1], sn[1], sv[1], dom, WH2, WHx, nl);
/* prettier-ignore */
this.createPart('mjx-ext', parts[1], sn[1], sv[1], dom, WH2, WHx, nl, WHm / 2, WHe);
}
this.createPart('mjx-end', parts[2], sn[2], sv[2], dom);
}
Expand All @@ -359,6 +364,8 @@ export const ChtmlMo = (function <N, T, D>(): ChtmlMoClass<N, T, D> {
* @param {number} W The extension width
* @param {number} Wx The width of the extender character
* @param {string} nl Character to use between extenders
* @param {number} Wb The beginning width
* @param {number} We The ending width
*/
protected createPart(
part: string,
Expand All @@ -368,7 +375,9 @@ export const ChtmlMo = (function <N, T, D>(): ChtmlMoClass<N, T, D> {
dom: N[],
W: number = 0,
Wx: number = 0,
nl: string = ''
nl: string = '',
Wb: number = 0,
We: number = 0
) {
if (n) {
const options = data[3];
Expand All @@ -379,13 +388,28 @@ export const ChtmlMo = (function <N, T, D>(): ChtmlMoClass<N, T, D> {
const c = options.c || String.fromCodePoint(n);
let nodes = [] as (N | T)[];
if (part === 'mjx-ext' && (Wx || options.dx)) {
//
// If the top and bottom must overlap, adjust the border sizes and remove the clipping
//
if (W < 0 && nl) {
dom.push(
this.html(part, {
...(font ? { class: font } : {}),
style: {
'border-width': `${this.em(Wb + W / 2)} 0 ${this.em(We + W / 2)}`,
'clip-path': 'none',
},
})
);
return;
}
//
// Some combining characters are listed as width 0,
// so get "real" width from dx and take off some
// for the right bearing.
//
if (!Wx) {
Wx = Math.max(0.06, 2 * options.dx - 0.06);
Wx = Math.max(HFUZZ, 2 * options.dx - HFUZZ);
}
const n = Math.min(Math.ceil(W / Wx) + 1, 500);
if (options.cmb) {
Expand Down
5 changes: 5 additions & 0 deletions ts/output/common/FontData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@ import { retryAfter } from '../../util/Retries.js';
import { DIRECTION } from './Direction.js';
export { DIRECTION } from './Direction.js';

/*****************************************************************/

export const VFUZZ = 0.07; // overlap for vertical stretchy glyphs
export const HFUZZ = 0.07; // overlap for horizontal stretchy glyphs

/****************************************************************************/

/**
Expand Down
46 changes: 28 additions & 18 deletions ts/output/svg/Wrappers/mo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ import {
SvgDelimiterData,
SvgFontData,
SvgFontDataClass,
VFUZZ,
HFUZZ,
} from '../FontData.js';
import {
CommonMo,
Expand All @@ -41,11 +43,6 @@ import { MmlMo } from '../../../core/MmlTree/MmlNodes/mo.js';
import { BBox } from '../../../util/BBox.js';
import { DIRECTION, SvgCharData } from '../FontData.js';

/*****************************************************************/

const VFUZZ = 0.1; // overlap for vertical stretchy glyphs
const HFUZZ = 0.1; // overlap for horizontal stretchy glyphs

/*****************************************************************/
/**
* The SvgMo interface for the SVG Mo wrapper
Expand Down Expand Up @@ -333,27 +330,40 @@ export const SvgMo = (function <N, T, D>(): SvgMoClass<N, T, D> {
* @param {number} B The height of the bottom glyph in the delimiter
* @param {number} W The width of the stretched delimiter
*/
/* prettier-ignore */
protected addExtV(n: number, v: string, H: number, D: number, T: number, B: number, W: number) {
protected addExtV(
n: number,
v: string,
H: number,
D: number,
T: number,
B: number,
W: number
) {
if (!n) return;
T = Math.max(0, T - VFUZZ); // A little overlap on top
B = Math.max(0, B - VFUZZ); // A little overlap on bottom
T = Math.max(0, T - VFUZZ); // // A little overlap on top
B = Math.max(0, B - VFUZZ); // // A little overlap on bottom
const adaptor = this.adaptor;
const [h, d, w] = this.getChar(n, v);
const Y = H + D - T - B; // The height of the extender
const s = 1.5 * Y / (h + d); // Scale height by 1.5 to avoid bad ends
// (glyphs with rounded or anti-aliased ends don't stretch well,
// so this makes for sharper ends)
const y = (s * (h - d) - Y) / 2; // The bottom point to clip the extender
const Y = H + D - T - B; // // The height of the extender
const s = (1.5 * Y) / (h + d); // // Scale height by 1.5 to avoid bad ends
// // (glyphs with rounded or anti-aliased ends don't stretch well,
// // so this makes for sharper ends)
const y = (s * (h - d) - Y) / 2; // // The bottom point to clip the extender
if (Y <= 0) return;
const svg = this.svg('svg', {
width: this.fixed(w), height: this.fixed(Y),
y: this.fixed(B - D), x: this.fixed((W - w) / 2),
viewBox: [0, y, w, Y].map(x => this.fixed(x)).join(' ')
width: this.fixed(w),
height: this.fixed(Y),
y: this.fixed(B - D),
x: this.fixed((W - w) / 2),
viewBox: [0, y, w, Y].map((x) => this.fixed(x)).join(' '),
});
this.addGlyph(n, v, 0, 0, svg);
const glyph = adaptor.lastChild(svg);
adaptor.setAttribute(glyph as N, 'transform', `scale(1,${this.jax.fixed(s)})`);
adaptor.setAttribute(
glyph as N,
'transform',
`scale(1,${this.jax.fixed(s)})`
);
if (this.dom[0]) {
adaptor.append(this.dom[0], svg);
}
Expand Down