Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Combine unknown characters into a common <text> element. (mathjax/MathJax#2672) #903

Merged
merged 3 commits into from
Mar 11, 2023
Merged
Show file tree
Hide file tree
Changes from 2 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
51 changes: 37 additions & 14 deletions ts/output/common/Wrappers/TextNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -159,38 +159,61 @@ export function CommonTextNodeMixin<
bbox.w = w;
} else {
const chars = this.remappedText(text, variant);
let utext = '';
bbox.empty();
//
// Loop through the characters and add them in one by one
//
for (const char of chars) {
let [h, d, w, data] = this.getVariantChar(variant, char);
if (data.unknown) {
utext += String.fromCodePoint(char);
} else {
utext = this.addUtextBBox(bbox, utext, variant);
//
// Measure unknown characters using the DOM (if possible)
// Update the bounding box
//
const cbox = this.jax.measureText(String.fromCodePoint(char), variant);
w = cbox.w;
h = cbox.h;
d = cbox.d;
this.updateBBox(bbox, h, d, w);
bbox.ic = data.ic || 0;
bbox.sk = data.sk || 0;
bbox.dx = data.dx || 0;
}
//
// Update the bounding box
//
bbox.w += w;
if (h > bbox.h) bbox.h = h;
if (d > bbox.d) bbox.d = d;
bbox.ic = data.ic || 0;
bbox.sk = data.sk || 0;
bbox.dx = data.dx || 0;
}
this.addUtextBBox(bbox, utext, variant);
if (chars.length > 1) {
bbox.sk = 0;
}
bbox.clean();
}
}

/**
* @param {BBox} bbox The bounding box to update
* @param {string} utext The text whose size is to be added to the bbox
* @param {string} variant The mathvariant for the text
* @return {string} The new utext (blank)
*/
protected addUtextBBox(bbox: BBox, utext: string, variant: string): string {
if (utext) {
const {h, d, w} = this.jax.measureText(utext, variant);
this.updateBBox(bbox, h, d, w);
}
return '';
}

/**
* @param {BBox} bbox The bounding box to update
* @param {number} h The height to use
* @param {nunber} d The depth to use
* @param {number} w The width to add
*/
protected updateBBox(bbox: BBox, h: number, d: number, w: number) {
bbox.w += w;
if (h > bbox.h) bbox.h = h;
if (d > bbox.d) bbox.d = d;
}


/******************************************************/
/*
* TextNodes don't need these, since these properties
Expand Down
34 changes: 29 additions & 5 deletions ts/output/svg/Wrapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,11 @@ export class SvgWrapper<N, T, D> extends CommonWrapper<
*/
public dx: number = 0;

/**
* buffered unknown text
*/
protected utext: string = '';

/**
* @override
*/
Expand Down Expand Up @@ -464,33 +469,52 @@ export class SvgWrapper<N, T, D> extends CommonWrapper<
* @param {number} y The y-position of the character
* @param {N} parent The container for the character
* @param {string} variant The variant to use for the character
* @param {boolean} buffer True to collect unknown characters into one text element
* @return {number} The width of the character
*/
public placeChar(n: number, x: number, y: number, parent: N, variant: string = null): number {
public placeChar(n: number, x: number, y: number, parent: N,
variant: string = null, buffer: boolean = false): number {
if (variant === null) {
variant = this.variant;
}
const C = n.toString(16).toUpperCase();
const [ , , w, data] = this.getVariantChar(variant, n);
if ('p' in data) {
x += this.addUtext(x, y, parent, variant);
const path = (data.p ? 'M' + data.p + 'Z' : '');
this.place(x, y, this.adaptor.append(parent, this.charNode(variant, C, path)) as N);
} else if ('c' in data) {
x += this.addUtext(x, y, parent, variant);
const g = this.adaptor.append(parent, this.svg('g', {'data-c': C})) as N;
this.place(x, y, g);
x = 0;
for (const n of this.unicodeChars(data.c, variant)) {
x += this.placeChar(n, x, y, g, variant);
}
} else if (data.unknown) {
const char = String.fromCodePoint(n);
const text = this.adaptor.append(parent, this.jax.unknownText(char, variant)) as N;
this.place(x, y, text);
return this.jax.measureTextNodeWithCache(text, char, variant).w;
this.utext += String.fromCodePoint(n);
return (buffer ? 0 : this.addUtext(x, y, parent, variant));
}
return w;
}

/**
* @param {number} x The x-position of the text
* @param {number} y The y-position of the text
* @param {N} parent The container for the text
* @param {string} variant The variant to use for the string
*/
protected addUtext(x: number, y: number, parent: N, variant: string): number {
const c = this.utext;
if (!c) {
return 0;
}
this.utext = '';
const text = this.adaptor.append(parent, this.jax.unknownText(c, variant)) as N;
this.place(x, y, text);
return this.jax.measureTextNodeWithCache(text, c, variant).w;
}

/**
* @param {string} variant The name of the variant being used
* @param {string} C The hex string for the character code
Expand Down
10 changes: 6 additions & 4 deletions ts/output/svg/Wrappers/TextNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,22 +96,24 @@ export const SvgTextNode = (function <N, T, D>(): SvgTextNodeClass<N, T, D> {
* @override
*/
public toSVG(parents: N[]) {
const text = (this.node as TextNode).getText();
const adaptor = this.adaptor;
const variant = this.parent.variant;
const text = (this.node as TextNode).getText();
if (text.length === 0) return;
if (variant === '-explicitFont') {
this.dom = [this.adaptor.append(parents[0], this.jax.unknownText(text, variant)) as N];
this.dom = [adaptor.append(parents[0], this.jax.unknownText(text, variant)) as N];
} else {
const chars = this.remappedText(text, variant);
if (this.parent.childNodes.length > 1) {
parents = this.dom = [this.adaptor.append(parents[0], this.svg('g', {'data-mml-node': 'text'})) as N];
parents = this.dom = [adaptor.append(parents[0], this.svg('g', {'data-mml-node': 'text'})) as N];
} else {
this.dom = parents;
}
let x = 0;
for (const n of chars) {
x += this.placeChar(n, x, 0, parents[0], variant);
x += this.placeChar(n, x, 0, parents[0], variant, true);
}
this.addUtext(x, 0, parents[0], variant);
}
}

Expand Down