add initial marp implementation with sample content and build configuration

This commit is contained in:
2025-09-13 18:13:22 +02:00
parent dcacc9b409
commit e5f219507f
10319 changed files with 1402023 additions and 0 deletions
+829
View File
@@ -0,0 +1,829 @@
/*************************************************************
*
* Copyright (c) 2017-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview Implements the FontData class for character bbox data
* and stretchy delimiters.
*
* @author dpvc@mathjax.org (Davide Cervone)
*/
import {OptionList, defaultOptions, userOptions} from '../../util/Options.js';
import {StyleList} from '../../util/StyleList.js';
/****************************************************************************/
/**
* The extra options allowed in a CharData array
*/
export interface CharOptions {
ic?: number; // italic correction value
sk?: number; // skew value
dx?: number; // offset for combining characters
unknown?: boolean; // true if not found in the given variant
smp?: number; // Math Alphanumeric codepoint this char is mapped to
}
/****************************************************************************/
/**
* Data about a character
* [height, depth, width, {italic-correction, skew, options}]
*
* @template C The CharOptions type
*/
export type CharData<C extends CharOptions> =
[number, number, number] |
[number, number, number, C];
/**
* An object making character positions to character data
*
* @template C The CharOptions type
*/
export type CharMap<C extends CharOptions> = {
[n: number]: CharData<C>;
};
/**
* An object making variants to character maps
*
* @template C The CharOptions type
*/
export type CharMapMap<C extends CharOptions> = {
[name: string]: CharMap<C>;
};
/****************************************************************************/
/**
* Data for a variant
*
* @template C The CharOptions type
*/
export interface VariantData<C extends CharOptions> {
/**
* A list of CharMaps that must be updated when characters are
* added to this variant
*/
linked: CharMap<C>[];
/**
* The character data for this variant
*/
chars: CharMap<C>;
}
/**
* An object making variants names to variant data
*
* @template C The CharOptions type
* @template V The VariantData type
*/
export type VariantMap<C extends CharOptions, V extends VariantData<C>> = {
[name: string]: V;
};
/**
* Data to use to map unknown characters in a variant to a
* generic CSS font:
*
* [fontname, italic, bold]
*/
export type CssFontData = [string, boolean, boolean];
/**
* An object mapping a variant name to the CSS data needed for it
*/
export type CssFontMap = {
[name: string]: CssFontData;
};
/****************************************************************************/
/**
* Stretchy delimiter data
*/
export const enum DIRECTION {None, Vertical, Horizontal}
export const V = DIRECTION.Vertical;
export const H = DIRECTION.Horizontal;
/****************************************************************************/
/**
* Data needed for stretchy vertical and horizontal characters
*/
export type DelimiterData = {
dir: DIRECTION; // vertical or horizontal direction
sizes?: number[]; // Array of fixed sizes for this character
variants?: number[]; // The variants in which the different sizes can be found (if not the default)
schar?: number[]; // The character number to use for each size (if different from the default)
stretch?: number[]; // The unicode code points for the parts of multi-character versions [beg, ext, end, mid?]
stretchv?: number[]; // the variants to use for the stretchy characters (index into variant name array)
HDW?: number[]; // [h, d, w] (for vertical, h and d are the normal size, w is the multi-character width,
// for horizontal, h and d are the multi-character ones, w is for the normal size).
min?: number; // The minimum size a multi-character version can be
c?: number; // The character number (for aliased delimiters)
fullExt?: [number, number] // When present, extenders must be full sized, and the first number is
// the size of the extender, while the second is the total size of the ends
};
/**
* An object mapping character numbers to delimiter data
*
* @template D The DelimiterData type
*/
export type DelimiterMap<D extends DelimiterData> = {
[n: number]: D;
};
/**
* Delimiter data for a non-stretchy character
*/
export const NOSTRETCH: DelimiterData = {dir: DIRECTION.None};
/****************************************************************************/
/**
* Data for remapping characters
*/
export type RemapData = string;
export type RemapMap = {
[key: number]: RemapData;
};
export type RemapMapMap = {
[key: string]: RemapMap;
};
/**
* Character remapping data for Math Alphanumerics
*/
export type SmpMap = {
[c: number]: number;
};
/**
* Data for Math Alphanumeric conversion: starting positions for
* [Alpha, alpha, Greek, greek, Numbers]
*/
export type SmpData = [number, number, number?, number?, number?];
/****************************************************************************/
/**
* Font parameters (for TeX typesetting rules)
*/
export type FontParameters = {
x_height: number,
quad: number,
num1: number,
num2: number,
num3: number,
denom1: number,
denom2: number,
sup1: number,
sup2: number,
sup3: number,
sub1: number,
sub2: number,
sup_drop: number,
sub_drop: number,
delim1: number,
delim2: number,
axis_height: number,
rule_thickness: number,
big_op_spacing1: number,
big_op_spacing2: number,
big_op_spacing3: number,
big_op_spacing4: number,
big_op_spacing5: number,
surd_height: number,
scriptspace: number,
nulldelimiterspace: number,
delimiterfactor: number,
delimitershortfall: number,
min_rule_thickness: number,
separation_factor: number,
extra_ic: number
};
/****************************************************************************/
/**
* The FontData class (for storing character bounding box data by variant,
* and the stretchy delimiter data).
*
* @template C The CharOptions type
* @template V The VariantData type
* @template D The DelimiterData type
*/
export class FontData<C extends CharOptions, V extends VariantData<C>, D extends DelimiterData> {
/**
* Options for the font
*/
public static OPTIONS: OptionList = {
unknownFamily: 'serif' // Should use 'monospace' with LiteAdaptor
};
/**
* The name of the output jax this font data is for (used by extensions)
*/
public static JAX: string = 'common';
/**
* The name of the font that is being defined (used by extensions)
*/
public static NAME: string = '';
/**
* The standard variants to define
*/
public static defaultVariants = [
['normal'],
['bold', 'normal'],
['italic', 'normal'],
['bold-italic', 'italic', 'bold'],
['double-struck', 'bold'],
['fraktur', 'normal'],
['bold-fraktur', 'bold', 'fraktur'],
['script', 'italic'],
['bold-script', 'bold-italic', 'script'],
['sans-serif', 'normal'],
['bold-sans-serif', 'bold', 'sans-serif'],
['sans-serif-italic', 'italic', 'sans-serif'],
['sans-serif-bold-italic', 'bold-italic', 'bold-sans-serif'],
['monospace', 'normal']
];
/**
* The family, style, and weight to use for each variant (for unknown characters)
* The 'unknown' family is replaced by options.unknownFamily
*/
public static defaultCssFonts: CssFontMap = {
normal: ['unknown', false, false],
bold: ['unknown', false, true],
italic: ['unknown', true, false],
'bold-italic': ['unknown', true, true],
'double-struck': ['unknown', false, true],
fraktur: ['unknown', false, false],
'bold-fraktur': ['unknown', false, true],
script: ['cursive', false, false],
'bold-script': ['cursive', false, true],
'sans-serif': ['sans-serif', false, false],
'bold-sans-serif': ['sans-serif', false, true],
'sans-serif-italic': ['sans-serif', true, false],
'sans-serif-bold-italic': ['sans-serif', true, true],
monospace: ['monospace', false, false]
};
/**
* The default prefix for explicit font-family settings
*/
protected static defaultCssFamilyPrefix = '';
/**
* Variant locations in the Math Alphabnumerics block:
* [upper-alpha, lower-alpha, upper-Greek, lower-Greek, numbers]
*/
public static VariantSmp: {[name: string]: SmpData} = {
bold: [0x1D400, 0x1D41A, 0x1D6A8, 0x1D6C2, 0x1D7CE],
italic: [0x1D434, 0x1D44E, 0x1D6E2, 0x1D6FC],
'bold-italic': [0x1D468, 0x1D482, 0x1D71C, 0x1D736],
script: [0x1D49C, 0x1D4B6],
'bold-script': [0x1D4D0, 0x1D4EA],
fraktur: [0x1D504, 0x1D51E],
'double-struck': [0x1D538, 0x1D552, , , 0x1D7D8],
'bold-fraktur': [0x1D56C, 0x1D586],
'sans-serif': [0x1D5A0, 0x1D5BA, , , 0x1D7E2],
'bold-sans-serif': [0x1D5D4, 0x1D5EE, 0x1D756, 0x1D770, 0x1D7EC],
'sans-serif-italic': [0x1D608, 0x1D622],
'sans-serif-bold-italic': [0x1D63C, 0x1D656, 0x1D790, 0x1D7AA],
'monospace': [0x1D670, 0x1D68A, , , 0x1D7F6]
};
/**
* Character ranges to remap into Math Alphanumerics
*/
public static SmpRanges = [
[0, 0x41, 0x5A], // Upper-case alpha
[1, 0x61, 0x7A], // Lower-case alpha
[2, 0x391, 0x3A9], // Upper-case Greek
[3, 0x3B1, 0x3C9], // Lower-case Greek
[4, 0x30, 0x39] // Numbers
];
/**
* Characters to map back top other Unicode positions
* (holes in the Math Alphanumeric ranges)
*/
public static SmpRemap: SmpMap = {
0x1D455: 0x210E, // PLANCK CONSTANT
0x1D49D: 0x212C, // SCRIPT CAPITAL B
0x1D4A0: 0x2130, // SCRIPT CAPITAL E
0x1D4A1: 0x2131, // SCRIPT CAPITAL F
0x1D4A3: 0x210B, // SCRIPT CAPITAL H
0x1D4A4: 0x2110, // SCRIPT CAPITAL I
0x1D4A7: 0x2112, // SCRIPT CAPITAL L
0x1D4A8: 0x2133, // SCRIPT CAPITAL M
0x1D4AD: 0x211B, // SCRIPT CAPITAL R
0x1D4BA: 0x212F, // SCRIPT SMALL E
0x1D4BC: 0x210A, // SCRIPT SMALL G
0x1D4C4: 0x2134, // SCRIPT SMALL O
0x1D506: 0x212D, // BLACK-LETTER CAPITAL C
0x1D50B: 0x210C, // BLACK-LETTER CAPITAL H
0x1D50C: 0x2111, // BLACK-LETTER CAPITAL I
0x1D515: 0x211C, // BLACK-LETTER CAPITAL R
0x1D51D: 0x2128, // BLACK-LETTER CAPITAL Z
0x1D53A: 0x2102, // DOUBLE-STRUCK CAPITAL C
0x1D53F: 0x210D, // DOUBLE-STRUCK CAPITAL H
0x1D545: 0x2115, // DOUBLE-STRUCK CAPITAL N
0x1D547: 0x2119, // DOUBLE-STRUCK CAPITAL P
0x1D548: 0x211A, // DOUBLE-STRUCK CAPITAL Q
0x1D549: 0x211D, // DOUBLE-STRUCK CAPITAL R
0x1D551: 0x2124, // DOUBLE-STRUCK CAPITAL Z
};
/**
* Greek upper-case variants
*/
public static SmpRemapGreekU: SmpMap = {
0x2207: 0x19, // nabla
0x03F4: 0x11 // theta symbol
};
/**
* Greek lower-case variants
*/
public static SmpRemapGreekL: SmpMap = {
0x3D1: 0x1B, // theta symbol
0x3D5: 0x1D, // phi symbol
0x3D6: 0x1F, // omega symbol
0x3F0: 0x1C, // kappa symbol
0x3F1: 0x1E, // rho symbol
0x3F5: 0x1A, // lunate epsilon symbol
0x2202: 0x19 // partial differential
};
/**
* The default remappings
*/
protected static defaultAccentMap: RemapMap = {
0x0300: '\u02CB', // grave accent
0x0301: '\u02CA', // acute accent
0x0302: '\u02C6', // curcumflex
0x0303: '\u02DC', // tilde accent
0x0304: '\u02C9', // macron
0x0306: '\u02D8', // breve
0x0307: '\u02D9', // dot
0x0308: '\u00A8', // diaresis
0x030A: '\u02DA', // ring above
0x030C: '\u02C7', // caron
0x2192: '\u20D7',
0x2032: '\'',
0x2033: '\'\'',
0x2034: '\'\'\'',
0x2035: '`',
0x2036: '``',
0x2037: '```',
0x2057: '\'\'\'\'',
0x20D0: '\u21BC', // combining left harpoon
0x20D1: '\u21C0', // combining right harpoon
0x20D6: '\u2190', // combining left arrow
0x20E1: '\u2194', // combining left-right arrow
0x20F0: '*', // combining asterisk
0x20DB: '...', // combining three dots above
0x20DC: '....', // combining four dots above
0x20EC: '\u21C1', // combining low left harpoon
0x20ED: '\u21BD', // combining low right harpoon
0x20EE: '\u2190', // combining low left arrows
0x20EF: '\u2192' // combining low right arrows
};
/**
* Default map for characters inside <mo>
*/
protected static defaultMoMap: RemapMap = {
0x002D: '\u2212' // hyphen
};
/**
* Default map for characters inside <mn>
*/
protected static defaultMnMap: RemapMap = {
0x002D: '\u2212' // hyphen
};
/**
* The default font parameters for the font
*/
public static defaultParams: FontParameters = {
x_height: .442,
quad: 1,
num1: .676,
num2: .394,
num3: .444,
denom1: .686,
denom2: .345,
sup1: .413,
sup2: .363,
sup3: .289,
sub1: .15,
sub2: .247,
sup_drop: .386,
sub_drop: .05,
delim1: 2.39,
delim2: 1.0,
axis_height: .25,
rule_thickness: .06,
big_op_spacing1: .111,
big_op_spacing2: .167,
big_op_spacing3: .2,
big_op_spacing4: .6,
big_op_spacing5: .1,
surd_height: .075,
scriptspace: .05,
nulldelimiterspace: .12,
delimiterfactor: 901,
delimitershortfall: .3,
min_rule_thickness: 1.25, // in pixels
separation_factor: 1.75, // expansion factor for spacing e.g. between accents and base
extra_ic: .033 // extra spacing for scripts (compensate for not having actual ic values)
};
/**
* The default delimiter data
*/
protected static defaultDelimiters: DelimiterMap<any> = {};
/**
* The default character data
*/
protected static defaultChars: CharMapMap<any> = {};
/**
* The default variants for the fixed size stretchy delimiters
*/
protected static defaultSizeVariants: string[] = [];
/**
* The default variants for the assembly parts for stretchy delimiters
*/
protected static defaultStretchVariants: string[] = [];
/**
* The font options
*/
protected options: OptionList;
/**
* The actual variant information for this font
*/
protected variant: VariantMap<C, V> = {};
/**
* The actual delimiter information for this font
*/
protected delimiters: DelimiterMap<D> = {};
/**
* The actual size variants to use for this font
*/
protected sizeVariants: string[];
/**
* The actual stretchy variants to use for this font
*/
protected stretchVariants: string[];
/**
* The data to use to make variants to default fonts and css for unknown characters
*/
protected cssFontMap: CssFontMap = {};
/**
* A prefix to use for explicit font-family CSS settings
*/
public cssFamilyPrefix: string;
/**
* The character maps
*/
protected remapChars: RemapMapMap = {};
/**
* The actual font parameters for this font
*/
public params: FontParameters;
/**
* Factor by which to multiply italic correction for computation of delta in munderover
*/
public skewIcFactor: number = .75;
/**
* Any styles needed for the font
*/
protected _styles: StyleList;
/**
* @param {CharMap} font The font to check
* @param {number} n The character to get options for
* @return {CharOptions} The options for the character
*/
public static charOptions(font: CharMap<CharOptions>, n: number): CharOptions {
const char = font[n];
if (char.length === 3) {
(char as any)[3] = {};
}
return char[3];
}
/**
* Copies the data from the defaults to the instance
*
* @param {OptionList} options The options for this font
*
* @constructor
*/
constructor(options: OptionList = null) {
let CLASS = (this.constructor as typeof FontData);
this.options = userOptions(defaultOptions({}, CLASS.OPTIONS), options);
this.params = {...CLASS.defaultParams};
this.sizeVariants = [...CLASS.defaultSizeVariants];
this.stretchVariants = [...CLASS.defaultStretchVariants];
this.cssFontMap = {...CLASS.defaultCssFonts};
for (const name of Object.keys(this.cssFontMap)) {
if (this.cssFontMap[name][0] === 'unknown') {
this.cssFontMap[name][0] = this.options.unknownFamily;
}
}
this.cssFamilyPrefix = CLASS.defaultCssFamilyPrefix;
this.createVariants(CLASS.defaultVariants);
this.defineDelimiters(CLASS.defaultDelimiters);
for (const name of Object.keys(CLASS.defaultChars)) {
this.defineChars(name, CLASS.defaultChars[name]);
}
this.defineRemap('accent', CLASS.defaultAccentMap);
this.defineRemap('mo', CLASS.defaultMoMap);
this.defineRemap('mn', CLASS.defaultMnMap);
}
/**
* Returns list of styles needed for the font
*/
get styles(): StyleList {
return this._styles;
}
/**
* Sets styles needed for that font.
*/
set styles(style: StyleList) {
this._styles = style;
}
/**
* Creates the data structure for a variant -- an object with
* prototype chain that includes a copy of the linked variant,
* and then the inherited variant chain.
*
* The reason for this extra link is that for a mathvariant like
* bold-italic, you want to inherit from both the bold and
* italic variants, but the prototype chain can only inherit
* from one. So for bold-italic, we make an object that has a
* prototype consisting of a copy of the bold data, and add the
* italic data as the prototype chain. (Since this is a copy, we
* keep a record of this link so that if bold is changed later,
* we can update this copy. That is not needed for the prototype
* chain, since the prototypes are the actual objects, not
* copies.) We then use this bold-plus-italic object as the
* prototype chain for the bold-italic object
*
* That means that bold-italic will first look in its own object
* for specifically bold-italic glyphs that are defined there,
* then in the copy of the bold glyphs (only its top level is
* copied, not its prototype chain), and then the specifically
* italic glyphs, and then the prototype chain for italics,
* which is the normal glyphs. Effectively, this means
* bold-italic looks for bold-italic, then bold, then italic,
* then normal glyphs in order to find the given character.
*
* @param {string} name The new variant to create
* @param {string} inherit The variant to use if a character is not in this one
* @param {string} link A variant to search before the inherit one (but only
* its top-level object).
*/
public createVariant(name: string, inherit: string = null, link: string = null) {
let variant = {
linked: [] as CharMap<C>[],
chars: (inherit ? Object.create(this.variant[inherit].chars) : {}) as CharMap<C>
} as V;
if (link && this.variant[link]) {
Object.assign(variant.chars, this.variant[link].chars);
this.variant[link].linked.push(variant.chars);
variant.chars = Object.create(variant.chars);
}
this.remapSmpChars(variant.chars, name);
this.variant[name] = variant;
}
/**
* Create the mapping from Basic Latin and Greek blocks to
* the Math Alphanumeric block for a given variant.
*/
protected remapSmpChars(chars: CharMap<C>, name: string) {
const CLASS = (this.constructor as typeof FontData);
if (CLASS.VariantSmp[name]) {
const SmpRemap = CLASS.SmpRemap;
const SmpGreek = [null, null, CLASS.SmpRemapGreekU, CLASS.SmpRemapGreekL];
for (const [i, lo, hi] of CLASS.SmpRanges) {
const base = CLASS.VariantSmp[name][i];
if (!base) continue;
for (let n = lo; n <= hi; n++) {
if (n === 0x3A2) continue;
const smp = base + n - lo;
chars[n] = this.smpChar(SmpRemap[smp] || smp);
}
if (SmpGreek[i]) {
for (const n of Object.keys(SmpGreek[i]).map((x) => parseInt(x))) {
chars[n] = this.smpChar(base + SmpGreek[i][n]);
}
}
}
}
if (name === 'bold') {
chars[0x3DC] = this.smpChar(0x1D7CA);
chars[0x3DD] = this.smpChar(0x1D7CB);
}
}
/**
* @param {number} n Math Alphanumerics position for this remapping
* @return {CharData<C>} The character data for the remapping
*/
protected smpChar(n: number): CharData<C> {
return [ , , , {smp: n} as C];
}
/**
* Create a collection of variants
*
* @param {string[][]} variants Array of [name, inherit?, link?] values for
* the variants to define
*/
public createVariants(variants: string[][]) {
for (const variant of variants) {
this.createVariant(variant[0], variant[1], variant[2]);
}
}
/**
* Defines new character data in a given variant
* (We use Object.assign() here rather than the spread operator since
* the character maps are objeccts with prototypes, and we don't
* want to loose those by doing {...chars} or something similar.)
*
* @param {string} name The variant for these characters
* @param {CharMap} chars The characters to define
*/
public defineChars(name: string, chars: CharMap<C>) {
let variant = this.variant[name];
Object.assign(variant.chars, chars);
for (const link of variant.linked) {
Object.assign(link, chars);
}
}
/**
* Defines stretchy delimiters
*
* @param {DelimiterMap} delims The delimiters to define
*/
public defineDelimiters(delims: DelimiterMap<D>) {
Object.assign(this.delimiters, delims);
}
/**
* Defines a character remapping map
*
* @param {string} name The name of the map to define or augment
* @param {RemapMap} remap The characters to remap
*/
public defineRemap(name: string, remap: RemapMap) {
if (!this.remapChars.hasOwnProperty(name)) {
this.remapChars[name] = {};
}
Object.assign(this.remapChars[name], remap);
}
/**
* @param {number} n The delimiter character number whose data is desired
* @return {DelimiterData} The data for that delimiter (or undefined)
*/
public getDelimiter(n: number): DelimiterData {
return this.delimiters[n];
}
/**
* @param {number} n The delimiter character number whose variant is needed
* @param {number} i The index in the size array of the size whose variant is needed
* @return {string} The variant of the i-th size for delimiter n
*/
public getSizeVariant(n: number, i: number): string {
if (this.delimiters[n].variants) {
i = this.delimiters[n].variants[i];
}
return this.sizeVariants[i];
}
/**
* @param {number} n The delimiter character number whose variant is needed
* @param {number} i The index in the stretch array of the part whose variant is needed
* @return {string} The variant of the i-th part for delimiter n
*/
public getStretchVariant(n: number, i: number): string {
return this.stretchVariants[this.delimiters[n].stretchv ? this.delimiters[n].stretchv[i] : 0];
}
/**
* @param {string} name The variant whose character data is being querried
* @param {number} n The unicode number for the character to be found
* @return {CharData} The data for the given character (or undefined)
*/
public getChar(name: string, n: number): CharData<C> {
return this.variant[name].chars[n];
}
/**
* @param {string} name The name of the variant whose data is to be obtained
* @return {V} The data for the requested variant (or undefined)
*/
public getVariant(name: string): V {
return this.variant[name];
}
/**
* @param {string} variant The name of the variant whose data is to be obtained
* @return {CssFontData} The CSS data for the requested variant
*/
public getCssFont(variant: string): CssFontData {
return this.cssFontMap[variant] || ['serif', false, false];
}
/**
* @param {string} family The font camily to use
* @return {string} The family with the css prefix
*/
public getFamily(family: string): string {
return (this.cssFamilyPrefix ? this.cssFamilyPrefix + ', ' + family : family);
}
/**
* @param {string} name The name of the map to query
* @param {number} c The character to remap
* @return {string} The remapped character (or the original)
*/
public getRemappedChar(name: string, c: number): string {
const map = this.remapChars[name] || {} as RemapMap;
return map[c];
}
}
/**
* The class interface for the FontData class
*
* @template C The CharOptions type
* @template V The VariantData type
* @template D The DelimiterData type
*/
export interface FontDataClass<C extends CharOptions, V extends VariantData<C>, D extends DelimiterData> {
OPTIONS: OptionList;
defaultCssFonts: CssFontMap;
defaultVariants: string[][];
defaultParams: FontParameters;
/* tslint:disable-next-line:jsdoc-require */
charOptions(font: CharMap<C>, n: number): C;
new(...args: any[]): FontData<C, V, D>;
}
+365
View File
@@ -0,0 +1,365 @@
/*************************************************************
*
* Copyright (c) 2018-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview Implements utilities for notations for menclose elements
*
* @author dpvc@mathjax.org (Davide Cervone)
*/
import {AnyWrapper} from './Wrapper.js';
import {CommonMenclose} from './Wrappers/menclose.js';
/*****************************************************************/
export const ARROWX = 4, ARROWDX = 1, ARROWY = 2; // default relative arrowhead values
export const THICKNESS = .067; // default rule thickness
export const PADDING = .2; // default padding
export const SOLID = THICKNESS + 'em solid'; // a solid border
/*****************************************************************/
/**
* Shorthand for CommonMenclose
*/
export type Menclose = CommonMenclose<any, any, any>;
/**
* Top, right, bottom, left padding data
*/
export type PaddingData = [number, number, number, number];
/**
* The functions used for notation definitions
*
* @templare N The DOM node class
*/
export type Renderer<W extends AnyWrapper, N> = (node: W, child: N) => void;
export type BBoxExtender<W extends AnyWrapper> = (node: W) => PaddingData;
export type BBoxBorder<W extends AnyWrapper> = (node: W) => PaddingData;
export type Initializer<W extends AnyWrapper> = (node: W) => void;
/**
* The definition of a notation
*
* @template W The menclose wrapper class
* @templare N The DOM node class
*/
export type NotationDef<W extends AnyWrapper, N> = {
renderer: Renderer<W, N>; // renders the DOM nodes for the notation
bbox: BBoxExtender<W>; // gives the offsets to the child bounding box: [top, right, bottom, left]
border?: BBoxBorder<W>; // gives the amount of the bbox offset that is due to borders on the child
renderChild?: boolean; // true if the notation is used to render the child directly (e.g., radical)
init?: Initializer<W>; // function to be called during wrapper construction
remove?: string; // list of notations that are suppressed by this one
};
/**
* For defining notation maps
*
* @template W The menclose wrapper class
* @templare N The DOM node class
*/
export type DefPair<W extends AnyWrapper, N> = [string, NotationDef<W, N>];
export type DefList<W extends AnyWrapper, N> = Map<string, NotationDef<W, N>>;
export type DefPairF<T, W extends AnyWrapper, N> = (name: T) => DefPair<W, N>;
/**
* The list of notations for an menclose element
*
* @template W The menclose wrapper class
* @templare N The DOM node class
*/
export type List<W extends AnyWrapper, N> = {[notation: string]: NotationDef<W, N>};
/*****************************************************************/
/**
* The names and indices of sides for borders, padding, etc.
*/
export const sideIndex = {top: 0, right: 1, bottom: 2, left: 3};
export type Side = keyof typeof sideIndex;
export const sideNames = Object.keys(sideIndex) as Side[];
/**
* Common BBox and Border functions
*/
export const fullBBox = ((node) => new Array(4).fill(node.thickness + node.padding)) as BBoxExtender<Menclose>;
export const fullPadding = ((node) => new Array(4).fill(node.padding)) as BBoxExtender<Menclose>;
export const fullBorder = ((node) => new Array(4).fill(node.thickness)) as BBoxBorder<Menclose>;
/*****************************************************************/
/**
* The length of an arrowhead
*/
export const arrowHead = (node: Menclose) => {
return Math.max(node.padding, node.thickness * (node.arrowhead.x + node.arrowhead.dx + 1));
};
/**
* Adjust short bbox for tall arrow heads
*/
export const arrowBBoxHD = (node: Menclose, TRBL: PaddingData) => {
if (node.childNodes[0]) {
const {h, d} = node.childNodes[0].getBBox();
TRBL[0] = TRBL[2] = Math.max(0, node.thickness * node.arrowhead.y - (h + d) / 2);
}
return TRBL;
};
/**
* Adjust thin bbox for wide arrow heads
*/
export const arrowBBoxW = (node: Menclose, TRBL: PaddingData) => {
if (node.childNodes[0]) {
const {w} = node.childNodes[0].getBBox();
TRBL[1] = TRBL[3] = Math.max(0, node.thickness * node.arrowhead.y - w / 2);
}
return TRBL;
};
/**
* The data for horizontal and vertical arrow notations
* [angle, double, isVertical, remove]
*/
export const arrowDef = {
up: [-Math.PI / 2, false, true, 'verticalstrike'],
down: [ Math.PI / 2, false, true, 'verticakstrike'],
right: [ 0, false, false, 'horizontalstrike'],
left: [ Math.PI, false, false, 'horizontalstrike'],
updown: [ Math.PI / 2, true, true, 'verticalstrike uparrow downarrow'],
leftright: [ 0, true, false, 'horizontalstrike leftarrow rightarrow']
} as {[name: string]: [number, boolean, boolean, string]};
/**
* The data for diagonal arrow notations
* [c, pi, double, remove]
*/
export const diagonalArrowDef = {
updiagonal: [-1, 0, false, 'updiagonalstrike northeastarrow'],
northeast: [-1, 0, false, 'updiagonalstrike updiagonalarrow'],
southeast: [ 1, 0, false, 'downdiagonalstrike'],
northwest: [ 1, Math.PI, false, 'downdiagonalstrike'],
southwest: [-1, Math.PI, false, 'updiagonalstrike'],
northeastsouthwest: [-1, 0, true, 'updiagonalstrike northeastarrow updiagonalarrow southwestarrow'],
northwestsoutheast: [ 1, 0, true, 'downdiagonalstrike northwestarrow southeastarrow']
} as {[name: string]: [number, number, boolean, string]};
/**
* The BBox functions for horizontal and vertical arrows
*/
export const arrowBBox = {
up: (node) => arrowBBoxW(node, [arrowHead(node), 0, node.padding, 0]),
down: (node) => arrowBBoxW(node, [node.padding, 0, arrowHead(node), 0]),
right: (node) => arrowBBoxHD(node, [0, arrowHead(node), 0, node.padding]),
left: (node) => arrowBBoxHD(node, [0, node.padding, 0, arrowHead(node)]),
updown: (node) => arrowBBoxW(node, [arrowHead(node), 0, arrowHead(node), 0]),
leftright: (node) => arrowBBoxHD(node, [0, arrowHead(node), 0, arrowHead(node)])
} as {[name: string]: BBoxExtender<Menclose>};
/*****************************************************************/
/**
* @param {Renderer} render The function for adding the border to the node
* @return {string => DefPair} The function returingn the notation definition
* for the notation having a line on the given side
*/
export const CommonBorder = function<W extends Menclose, N>(render: Renderer<W, N>): DefPairF<Side, W, N> {
/**
* @param {string} side The side on which a border should appear
* @return {DefPair} The notation definition for the notation having a line on the given side
*/
return (side: Side) => {
const i = sideIndex[side];
return [side, {
//
// Add the border to the main child object
//
renderer: render,
//
// Indicate the extra space on the given side
//
bbox: (node) => {
const bbox = [0, 0, 0, 0] as PaddingData;
bbox[i] = node.thickness + node.padding;
return bbox;
},
//
// Indicate the border on the given side
//
border: (node) => {
const bbox = [0, 0, 0, 0] as PaddingData;
bbox[i] = node.thickness;
return bbox;
}
}];
};
};
/**
* @param {Renderer} render The function for adding the borders to the node
* @return {(sring, Side, Side) => DefPair} The function returning the notation definition
* for the notation having lines on two sides
*/
export const CommonBorder2 = function<W extends Menclose, N>(render: Renderer<W, N>):
(name: string, side1: Side, side2: Side) => DefPair<W, N> {
/**
* @param {string} name The name of the notation to define
* @param {Side} side1 The first side to get a border
* @param {Side} side2 The second side to get a border
* @return {DefPair} The notation definition for the notation having lines on two sides
*/
return (name: string, side1: Side, side2: Side) => {
const i1 = sideIndex[side1];
const i2 = sideIndex[side2];
return [name, {
//
// Add the border along the given sides
//
renderer: render,
//
// Mark the extra space along the two sides
//
bbox: (node) => {
const t = node.thickness + node.padding;
const bbox = [0, 0, 0, 0] as PaddingData;
bbox[i1] = bbox[i2] = t;
return bbox;
},
//
// Indicate the border on the two sides
//
border: (node) => {
const bbox = [0, 0, 0, 0] as PaddingData;
bbox[i1] = bbox[i2] = node.thickness;
return bbox;
},
//
// Remove the single side notations, if present
//
remove: side1 + ' ' + side2
}];
};
};
/*****************************************************************/
/**
* @param {string => Renderer} render The function for adding the strike to the node
* @return {string => DefPair} The function returning the notation definition for the diagonal strike
*/
export const CommonDiagonalStrike = function<W extends Menclose, N>(render: (sname: string) => Renderer<W, N>):
DefPairF<string, W, N> {
/**
* @param {string} name The name of the diagonal strike to define
* @return {DefPair} The notation definition for the diagonal strike
*/
return (name: string) => {
const cname = 'mjx-' + name.charAt(0) + 'strike';
return [name + 'diagonalstrike', {
//
// Find the angle and width from the bounding box size and create the diagonal line
//
renderer: render(cname),
//
// Add padding all around
//
bbox: fullBBox
}];
};
};
/*****************************************************************/
/**
* @param {Renderer} render The function to add the arrow to the node
* @return {string => DefPair} The funciton returning the notation definition for the diagonal arrow
*/
export const CommonDiagonalArrow = function<W extends Menclose, N>(render: Renderer<W, N>): DefPairF<string, W, N> {
/**
* @param {string} name The name of the diagonal arrow to define
* @return {DefPair} The notation definition for the diagonal arrow
*/
return (name: string) => {
const [c, pi, double, remove] = diagonalArrowDef[name];
return [name + 'arrow', {
//
// Find the angle and width from the bounding box size and create
// the arrow from them and the other arrow data
//
renderer: (node, _child) => {
const [a, W] = node.arrowAW();
const arrow = node.arrow(W, c * (a - pi), double);
render(node, arrow);
},
//
// Add space for the arrowhead all around
//
bbox: (node) => {
const {a, x, y} = node.arrowData();
const [ax, ay, adx] = [node.arrowhead.x, node.arrowhead.y, node.arrowhead.dx];
const [b, ar] = node.getArgMod(ax + adx, ay);
const dy = y + (b > a ? node.thickness * ar * Math.sin(b - a) : 0);
const dx = x + (b > Math.PI / 2 - a ? node.thickness * ar * Math.sin(b + a - Math.PI / 2) : 0);
return [dy, dx, dy, dx];
},
//
// Remove redundant notations
//
remove: remove
}];
};
};
/**
* @param {Renderer} render The function to add the arrow to the node
* @return {string => DefPair} The function returning the notation definition for the arrow
*/
export const CommonArrow = function<W extends Menclose, N>(render: Renderer<W, N>): DefPairF<string, W, N> {
/**
* @param {string} name The name of the horizontal or vertical arrow to define
* @return {DefPair} The notation definition for the arrow
*/
return (name: string) => {
const [angle, double, isVertical, remove] = arrowDef[name];
return [name + 'arrow', {
//
// Get the arrow height and depth from the bounding box and the arrow direction
// then create the arrow from that and the other data
//
renderer: (node, _child) => {
const {w, h, d} = node.getBBox();
const [W, offset] = (isVertical ? [h + d, 'X'] : [w, 'Y']);
const dd = node.getOffset(offset);
const arrow = node.arrow(W, angle, double, offset, dd);
render(node, arrow);
},
//
// Add the padding to the proper sides
//
bbox: arrowBBox[name],
//
// Remove redundant notations
//
remove: remove
}];
};
};
+661
View File
@@ -0,0 +1,661 @@
/*************************************************************
*
* Copyright (c) 2017-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview Implements the abstract class for the CommonOutputJax
*
* @author dpvc@mathjax.org (Davide Cervone)
*/
import {AbstractOutputJax} from '../../core/OutputJax.js';
import {MathDocument} from '../../core/MathDocument.js';
import {MathItem, Metrics, STATE} from '../../core/MathItem.js';
import {MmlNode} from '../../core/MmlTree/MmlNode.js';
import {FontData, FontDataClass, CharOptions, DelimiterData, CssFontData} from './FontData.js';
import {OptionList, separateOptions} from '../../util/Options.js';
import {CommonWrapper, AnyWrapper, AnyWrapperClass} from './Wrapper.js';
import {CommonWrapperFactory, AnyWrapperFactory} from './WrapperFactory.js';
import {percent} from '../../util/lengths.js';
import {StyleList, Styles} from '../../util/Styles.js';
import {StyleList as CssStyleList, CssStyles} from '../../util/StyleList.js';
/*****************************************************************/
export interface ExtendedMetrics extends Metrics {
family: string; // the font family for the surrounding text
}
/**
* Maps linking a node to the test node it contains,
* and a map linking a node to the metrics within that node.
*/
export type MetricMap<N> = Map<N, ExtendedMetrics>;
type MetricDomMap<N> = Map<N, N>;
/**
* Maps for unknown characters
*/
export type UnknownBBox = {w: number, h: number, d: number};
export type UnknownMap = Map<string, UnknownBBox>;
export type UnknownVariantMap = Map<string, UnknownMap>;
/*****************************************************************/
/**
* The CommonOutputJax class on which the CHTML and SVG jax are built
*
* @template N The HTMLElement node class
* @template T The Text node class
* @template D The Document class
* @template W The Wrapper class
* @template F The WrapperFactory class
* @template FD The FontData class
* @template FC The FontDataClass object
*/
export abstract class CommonOutputJax<
N, T, D,
W extends AnyWrapper,
F extends AnyWrapperFactory,
FD extends FontData<any, any, any>,
FC extends FontDataClass<any, any, any>
> extends AbstractOutputJax<N, T, D> {
/**
* The name of this output jax
*/
public static NAME: string = 'Common';
/**
* @override
*/
public static OPTIONS: OptionList = {
...AbstractOutputJax.OPTIONS,
scale: 1, // global scaling factor for all expressions
minScale: .5, // smallest scaling factor to use
mtextInheritFont: false, // true to make mtext elements use surrounding font
merrorInheritFont: false, // true to make merror text use surrounding font
mtextFont: '', // font to use for mtext, if not inheriting (empty means use MathJax fonts)
merrorFont: 'serif', // font to use for merror, if not inheriting (empty means use MathJax fonts)
mathmlSpacing: false, // true for MathML spacing rules, false for TeX rules
skipAttributes: {}, // RFDa and other attributes NOT to copy to the output
exFactor: .5, // default size of ex in em units
displayAlign: 'center', // default for indentalign when set to 'auto'
displayIndent: '0', // default for indentshift when set to 'auto'
wrapperFactory: null, // The wrapper factory to use
font: null, // The FontData object to use
cssStyles: null // The CssStyles object to use
};
/**
* The default styles for the output jax
*/
public static commonStyles: CssStyleList = {};
/**
* Used for collecting styles needed for the output jax
*/
public cssStyles: CssStyles;
/**
* The MathDocument for the math we find
*/
public document: MathDocument<N, T, D>;
/**
* the MathItem currently being processed
*/
public math: MathItem<N, T, D>;
/**
* The container element for the math
*/
public container: N;
/**
* The top-level table, if any
*/
public table: AnyWrapper;
/**
* The pixels per em for the math item being processed
*/
public pxPerEm: number;
/**
* The data for the font in use
*/
public font: FD;
/**
* The wrapper factory for the MathML nodes
*/
public factory: F;
/**
* A map from the nodes in the expression currently being processed to the
* wrapper nodes for them (used by functions like core() to locate the wrappers
* from the core nodes)
*/
public nodeMap: Map<MmlNode, W>;
/**
* Node used to test for in-line metric data
*/
public testInline: N;
/**
* Node used to test for display metric data
*/
public testDisplay: N;
/**
* Cache of unknonw character bounding boxes for this element
*/
protected unknownCache: UnknownVariantMap;
/*****************************************************************/
/**
* Get the WrapperFactory and connect it to this output jax
* Get the cssStyle and font objects
*
* @param {OptionList} options The configuration options
* @param {CommonWrapperFactory} defaultFactory The default wrapper factory class
* @param {FC} defaultFont The default FontData constructor
* @constructor
*/
constructor(options: OptionList = null,
defaultFactory: typeof CommonWrapperFactory = null,
defaultFont: FC = null) {
const [jaxOptions, fontOptions] = separateOptions(options, defaultFont.OPTIONS);
super(jaxOptions);
this.factory = this.options.wrapperFactory ||
new defaultFactory<CommonOutputJax<N, T, D, W, F, FD, FC>, W,
AnyWrapperClass, CharOptions, DelimiterData, FD>();
this.factory.jax = this;
this.cssStyles = this.options.cssStyles || new CssStyles();
this.font = this.options.font || new defaultFont(fontOptions);
this.unknownCache = new Map();
}
/*****************************************************************/
/**
* Save the math document
* Create the mjx-container node
* Create the DOM output for the root MathML math node in the container
* Return the container node
*
* @override
*/
public typeset(math: MathItem<N, T, D>, html: MathDocument<N, T, D>) {
this.setDocument(html);
let node = this.createNode();
this.toDOM(math, node, html);
return node;
}
/**
* @return {N} The container DOM node for the typeset math
*/
protected createNode(): N {
const jax = (this.constructor as typeof CommonOutputJax).NAME;
return this.html('mjx-container', {'class': 'MathJax', jax: jax});
}
/**
* @param {N} node The container whose scale is to be set
*/
protected setScale(node: N) {
const scale = this.math.metrics.scale * this.options.scale;
if (scale !== 1) {
this.adaptor.setStyle(node, 'fontSize', percent(scale));
}
}
/**
* Save the math document, if any, and the math item
* Set the document where HTML nodes will be created via the adaptor
* Recursively set the TeX classes for the nodes
* Set the scaling for the DOM node
* Create the nodeMap (maps MathML nodes to corresponding wrappers)
* Create the HTML output for the root MathML node in the container
* Clear the nodeMape
* Execute the post-filters
*
* @param {MathItem} math The math item to convert
* @param {N} node The contaier to place the result into
* @param {MathDocument} html The document containing the math
*/
public toDOM(math: MathItem<N, T, D>, node: N, html: MathDocument<N, T, D> = null) {
this.setDocument(html);
this.math = math;
this.pxPerEm = math.metrics.ex / this.font.params.x_height;
math.root.setTeXclass(null);
this.setScale(node);
this.nodeMap = new Map<MmlNode, W>();
this.container = node;
this.processMath(math.root, node);
this.nodeMap = null;
this.executeFilters(this.postFilters, math, html, node);
}
/**
* This is the actual typesetting function supplied by the subclass
*
* @param {MmlNode} math The intenral MathML node of the root math element to process
* @param {N} node The container node where the math is to be typeset
*/
protected abstract processMath(math: MmlNode, node: N): void;
/*****************************************************************/
/**
* @param {MathItem} math The MathItem to get the bounding box for
* @param {MathDocument} html The MathDocument for the math
*/
public getBBox(math: MathItem<N, T, D>, html: MathDocument<N, T, D>) {
this.setDocument(html);
this.math = math;
math.root.setTeXclass(null);
this.nodeMap = new Map<MmlNode, W>();
let bbox = this.factory.wrap(math.root).getOuterBBox();
this.nodeMap = null;
return bbox;
}
/*****************************************************************/
/**
* @override
*/
public getMetrics(html: MathDocument<N, T, D>) {
this.setDocument(html);
const adaptor = this.adaptor;
const maps = this.getMetricMaps(html);
for (const math of html.math) {
const parent = adaptor.parent(math.start.node);
if (math.state() < STATE.METRICS && parent) {
const map = maps[math.display ? 1 : 0];
const {em, ex, containerWidth, lineWidth, scale, family} = map.get(parent);
math.setMetrics(em, ex, containerWidth, lineWidth, scale);
if (this.options.mtextInheritFont) {
math.outputData.mtextFamily = family;
}
if (this.options.merrorInheritFont) {
math.outputData.merrorFamily = family;
}
math.state(STATE.METRICS);
}
}
}
/**
* @param {N} node The container node whose metrics are to be measured
* @param {boolean} display True if the metrics are for displayed math
* @return {Metrics} Object containing em, ex, containerWidth, etc.
*/
public getMetricsFor(node: N, display: boolean): ExtendedMetrics {
const getFamily = (this.options.mtextInheritFont || this.options.merrorInheritFont);
const test = this.getTestElement(node, display);
const metrics = this.measureMetrics(test, getFamily);
this.adaptor.remove(test);
return metrics;
}
/**
* Get a MetricMap for the math list
*
* @param {MathDocument} html The math document whose math list is to be processed.
* @return {MetricMap[]} The node-to-metrics maps for all the containers that have math
*/
protected getMetricMaps(html: MathDocument<N, T, D>): MetricMap<N>[] {
const adaptor = this.adaptor;
const domMaps = [new Map() as MetricDomMap<N>, new Map() as MetricDomMap<N>];
//
// Add the test elements all at once (so only one reflow)
// Currently, we do one test for each container element for in-line and one for display math
// (since we need different techniques for the two forms to avoid a WebKit bug).
// This may need to be changed to handle floating elements better, since that has to be
// done at the location of the math itself, not necessarily the end of the container.
//
for (const math of html.math) {
const node = adaptor.parent(math.start.node);
if (node && math.state() < STATE.METRICS) {
const map = domMaps[math.display ? 1 : 0];
if (!map.has(node)) {
map.set(node, this.getTestElement(node, math.display));
}
}
}
//
// Measure the metrics for all the mapped elements
//
const getFamily = this.options.mtextInheritFont || this.options.merrorInheritFont;
const maps = [new Map() as MetricMap<N>, new Map() as MetricMap<N>];
for (const i of maps.keys()) {
for (const node of domMaps[i].keys()) {
maps[i].set(node, this.measureMetrics(domMaps[i].get(node), getFamily));
}
}
//
// Remove the test elements
//
for (const i of maps.keys()) {
for (const node of domMaps[i].values()) {
adaptor.remove(node);
}
}
return maps;
}
/**
* @param {N} node The math element to be measured
* @return {N} The test elements that were added
*/
protected getTestElement(node: N, display: boolean): N {
const adaptor = this.adaptor;
if (!this.testInline) {
this.testInline = this.html('mjx-test', {style: {
display: 'inline-block',
width: '100%',
'font-style': 'normal',
'font-weight': 'normal',
'font-size': '100%',
'font-size-adjust': 'none',
'text-indent': 0,
'text-transform': 'none',
'letter-spacing': 'normal',
'word-spacing': 'normal',
overflow: 'hidden',
height: '1px',
'margin-right': '-1px'
}}, [
this.html('mjx-left-box', {style: {
display: 'inline-block',
width: 0,
'float': 'left'
}}),
this.html('mjx-ex-box', {style: {
position: 'absolute',
overflow: 'hidden',
width: '1px', height: '60ex'
}}),
this.html('mjx-right-box', {style: {
display: 'inline-block',
width: 0,
'float': 'right'
}})
]);
this.testDisplay = adaptor.clone(this.testInline);
adaptor.setStyle(this.testDisplay, 'display', 'table');
adaptor.setStyle(this.testDisplay, 'margin-right', '');
adaptor.setStyle(adaptor.firstChild(this.testDisplay) as N, 'display', 'none');
const right = adaptor.lastChild(this.testDisplay) as N;
adaptor.setStyle(right, 'display', 'table-cell');
adaptor.setStyle(right, 'width', '10000em');
adaptor.setStyle(right, 'float', '');
}
return adaptor.append(node, adaptor.clone(display ? this.testDisplay : this.testInline) as N) as N;
}
/**
* @param {N} node The test node to measure
* @param {boolean} getFamily True if font family of surroundings is to be determined
* @return {ExtendedMetrics} The metric data for the given node
*/
protected measureMetrics(node: N, getFamily: boolean): ExtendedMetrics {
const adaptor = this.adaptor;
const family = (getFamily ? adaptor.fontFamily(node) : '');
const em = adaptor.fontSize(node);
const [w, h] = adaptor.nodeSize(adaptor.childNode(node, 1) as N);
const ex = (w ? h / 60 : em * this.options.exFactor);
const containerWidth = (!w ? 1000000 : adaptor.getStyle(node, 'display') === 'table' ?
adaptor.nodeSize(adaptor.lastChild(node) as N)[0] - 1 :
adaptor.nodeBBox(adaptor.lastChild(node) as N).left -
adaptor.nodeBBox(adaptor.firstChild(node) as N).left - 2);
const scale = Math.max(this.options.minScale,
this.options.matchFontHeight ? ex / this.font.params.x_height / em : 1);
const lineWidth = 1000000; // no linebreaking (otherwise would be a percentage of cwidth)
return {em, ex, containerWidth, lineWidth, scale, family};
}
/*****************************************************************/
/**
* @override
*/
public styleSheet(html: MathDocument<N, T, D>) {
this.setDocument(html);
//
// Start with the common styles
//
this.cssStyles.clear();
this.cssStyles.addStyles((this.constructor as typeof CommonOutputJax).commonStyles);
//
// Add document-specific styles
//
if ('getStyles' in html) {
for (const styles of ((html as any).getStyles() as CssStyleList[])) {
this.cssStyles.addStyles(styles);
}
}
//
// Gather the CSS from the classes and font
//
this.addWrapperStyles(this.cssStyles);
this.addFontStyles(this.cssStyles);
//
// Create the stylesheet for the CSS
//
const sheet = this.html('style', {id: 'MJX-styles'}, [this.text('\n' + this.cssStyles.cssText + '\n')]);
return sheet as N;
}
/**
* @param {CssStyles} styles The style object to add to
*/
protected addFontStyles(styles: CssStyles) {
styles.addStyles(this.font.styles);
}
/**
* @param {CssStyles} styles The style object to add to
*/
protected addWrapperStyles(styles: CssStyles) {
for (const kind of this.factory.getKinds()) {
this.addClassStyles(this.factory.getNodeClass(kind), styles);
}
}
/**
* @param {typeof CommonWrapper} CLASS The Wrapper class whose styles are to be added
* @param {CssStyles} styles The style object to add to.
*/
protected addClassStyles(CLASS: typeof CommonWrapper, styles: CssStyles) {
styles.addStyles(CLASS.styles);
}
/*****************************************************************/
/**
* @param {MathDocument} html The document to be used
*/
protected setDocument(html: MathDocument<N, T, D>) {
if (html) {
this.document = html;
this.adaptor.document = html.document;
}
}
/**
* @param {string} type The type of HTML node to create
* @param {OptionList} def The properties to set on the HTML node
* @param {(N|T)[]} content Array of child nodes to set for the HTML node
* @param {string} ns The namespace for the element
* @return {N} The newly created DOM tree
*/
public html(type: string, def: OptionList = {}, content: (N | T)[] = [], ns?: string): N {
return this.adaptor.node(type, def, content, ns);
}
/**
* @param {string} text The text string for which to make a text node
*
* @return {T} A text node with the given text
*/
public text(text: string): T {
return this.adaptor.text(text);
}
/**
* @param {number} m A number to be shown with a fixed number of digits
* @param {number=} n The number of digits to use
* @return {string} The formatted number
*/
public fixed(m: number, n: number = 3): string {
if (Math.abs(m) < .0006) {
return '0';
}
return m.toFixed(n).replace(/\.?0+$/, '');
}
/*****************************************************************/
/*
* Methods for handling text that is not in the current MathJax font
*/
/**
* Create a DOM node for text from a specific CSS font, or that is
* not in the current MathJax font
*
* @param {string} text The text to be displayed
* @param {string} variant The name of the variant for the text
* @return {N} The text element containing the text
*/
public abstract unknownText(text: string, variant: string): N;
/**
* Measure text from a specific font, or that isn't in the MathJax font
*
* @param {string} text The text to measure
* @param {string} variant The variant for the text
* @param {CssFontData} font The family, italic, and bold data for explicit fonts
* @return {UnknownBBox} The width, height, and depth of the text (in ems)
*/
public measureText(text: string, variant: string, font: CssFontData = ['', false, false]): UnknownBBox {
const node = this.unknownText(text, variant);
if (variant === '-explicitFont') {
const styles = this.cssFontStyles(font);
this.adaptor.setAttributes(node, {style: styles});
}
return this.measureTextNodeWithCache(node, text, variant, font);
}
/**
* Get the size of a text node, caching the result, and using
* a cached result, if there is one.
*
* @param {N} text The text element to measure
* @param {string} chars The string contained in the text node
* @param {string} variant The variant for the text
* @param {CssFontData} font The family, italic, and bold data for explicit fonts
* @return {UnknownBBox} The width, height and depth for the text
*/
public measureTextNodeWithCache(
text: N, chars: string, variant: string,
font: CssFontData = ['', false, false]
): UnknownBBox {
if (variant === '-explicitFont') {
variant = [font[0], font[1] ? 'T' : 'F', font[2] ? 'T' : 'F', ''].join('-');
}
if (!this.unknownCache.has(variant)) {
this.unknownCache.set(variant, new Map());
}
const map = this.unknownCache.get(variant);
const cached = map.get(chars);
if (cached) return cached;
const bbox = this.measureTextNode(text);
map.set(chars, bbox);
return bbox;
}
/**
* Measure the width of a text element by placing it in the page
* and looking up its size (fake the height and depth, since we can't measure that)
*
* @param {N} text The text element to measure
* @return {UnknownBBox} The width, height and depth for the text (in ems)
*/
public abstract measureTextNode(text: N): UnknownBBox;
/**
* Measure the width, height and depth of an annotation-xml node's content
*
* @param{N} xml The xml content node to be measured
* @return {UnknownBBox} The width, height, and depth of the content
*/
public measureXMLnode(xml: N): UnknownBBox {
const adaptor = this.adaptor;
const content = this.html('mjx-xml-block', {style: {display: 'inline-block'}}, [adaptor.clone(xml)]);
const base = this.html('mjx-baseline', {style: {display: 'inline-block', width: 0, height: 0}});
const style = {
position: 'absolute',
display: 'inline-block',
'font-family': 'initial',
'line-height': 'normal'
};
const node = this.html('mjx-measure-xml', {style}, [base, content]);
adaptor.append(adaptor.parent(this.math.start.node), this.container);
adaptor.append(this.container, node);
const em = this.math.metrics.em * this.math.metrics.scale;
const {left, right, bottom, top} = adaptor.nodeBBox(content);
const w = (right - left) / em;
const h = (adaptor.nodeBBox(base).top - top) / em;
const d = (bottom - top) / em - h;
adaptor.remove(this.container);
adaptor.remove(node);
return {w, h, d};
}
/**
* @param {CssFontData} font The family, style, and weight for the given font
* @param {StyleList} styles The style object to add the font data to
* @return {StyleList} The modified (or initialized) style object
*/
public cssFontStyles(font: CssFontData, styles: StyleList = {}): StyleList {
const [family, italic, bold] = font;
styles['font-family'] = this.font.getFamily(family);
if (italic) styles['font-style'] = 'italic';
if (bold) styles['font-weight'] = 'bold';
return styles;
}
/**
* @param {Styles} styles The style object to query
* @return {CssFontData} The family, italic, and boolean values
*/
public getFontData(styles: Styles): CssFontData {
if (!styles) {
styles = new Styles();
}
return [this.font.getFamily(styles.get('font-family')),
styles.get('font-style') === 'italic',
styles.get('font-weight') === 'bold'] as CssFontData;
}
}
+845
View File
@@ -0,0 +1,845 @@
/*************************************************************
*
* Copyright (c) 2017-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview Implements the CommonWrapper class
*
* @author dpvc@mathjax.org (Davide Cervone)
*/
import {AbstractWrapper, WrapperClass} from '../../core/Tree/Wrapper.js';
import {PropertyList} from '../../core/Tree/Node.js';
import {MmlNode, TextNode, AbstractMmlNode, indentAttributes} from '../../core/MmlTree/MmlNode.js';
import {MmlMo} from '../../core/MmlTree/MmlNodes/mo.js';
import {Property} from '../../core/Tree/Node.js';
import {unicodeChars} from '../../util/string.js';
import * as LENGTHS from '../../util/lengths.js';
import {Styles} from '../../util/Styles.js';
import {StyleList} from '../../util/StyleList.js';
import {CommonOutputJax} from './OutputJax.js';
import {CommonWrapperFactory} from './WrapperFactory.js';
import {BBox} from '../../util/BBox.js';
import {FontData, DelimiterData, CharData, CharOptions, DIRECTION, NOSTRETCH} from './FontData.js';
/*****************************************************************/
/**
* Shorthand for a dictionary object (an object of key:value pairs)
*/
export type StringMap = {[key: string]: string};
/**
* MathML spacing rules
*/
/* tslint:disable-next-line:whitespace */
const SMALLSIZE = 2/18;
/**
* @param {boolean} script The scriptlevel
* @param {number} size The space size
* @return {number} The size clamped to SMALLSIZE when scriptlevel > 0
*/
function MathMLSpace(script: boolean, size: number): number {
return (script ? size < SMALLSIZE ? 0 : SMALLSIZE : size);
}
export type Constructor<T> = new(...args: any[]) => T;
/**
* Shorthands for wrappers and their constructors
*/
export type AnyWrapper = CommonWrapper<any, any, any, any, any, any>;
export type AnyWrapperClass = CommonWrapperClass<any, any, any, any, any, any>;
export type WrapperConstructor = Constructor<AnyWrapper>;
/*********************************************************/
/**
* The CommonWrapper class interface
*
* @template J The OutputJax type
* @template W The Wrapper type
* @template C The WrapperClass type
* @template CC The CharOptions type
* @template FD The FontData type
*/
export interface CommonWrapperClass<
J extends CommonOutputJax<any, any, any, W, CommonWrapperFactory<J, W, C, CC, DD, FD>, FD, any>,
W extends CommonWrapper<J, W, C, CC, DD, FD>,
C extends CommonWrapperClass<J, W, C, CC, DD, FD>,
CC extends CharOptions,
DD extends DelimiterData,
FD extends FontData<CC, any, DD>
> extends WrapperClass<MmlNode, CommonWrapper<J, W, C, CC, DD, FD>> {
/**
* @override
*/
new(factory: CommonWrapperFactory<J, W, C, CC, DD, FD>, node: MmlNode, ...args: any[]): W;
}
/*****************************************************************/
/**
* The base CommonWrapper class
*
* @template J The OutputJax type
* @template W The Wrapper type
* @template C The WrapperClass type
* @template CC The CharOptions type
* @template FD The FontData type
*/
export class CommonWrapper<
J extends CommonOutputJax<any, any, any, W, CommonWrapperFactory<J, W, C, CC, DD, FD>, FD, any>,
W extends CommonWrapper<J, W, C, CC, DD, FD>,
C extends CommonWrapperClass<J, W, C, CC, DD, FD>,
CC extends CharOptions,
DD extends DelimiterData,
FD extends FontData<CC, any, DD>
> extends AbstractWrapper<MmlNode, CommonWrapper<J, W, C, CC, DD, FD>> {
/**
* The wrapper kind
*/
public static kind: string = 'unknown';
/**
* Any styles needed for the class
*/
public static styles: StyleList = {};
/**
* Styles that should not be passed on from style attribute
*/
public static removeStyles: string[] = [
'fontSize', 'fontFamily', 'fontWeight',
'fontStyle', 'fontVariant', 'font'
];
/**
* Non-MathML attributes on MathML elements NOT to be copied to the
* corresponding DOM elements. If set to false, then the attribute
* WILL be copied. Most of these (like the font attributes) are handled
* in other ways.
*/
public static skipAttributes: {[name: string]: boolean} = {
fontfamily: true, fontsize: true, fontweight: true, fontstyle: true,
color: true, background: true,
'class': true, href: true, style: true,
xmlns: true
};
/**
* The translation of mathvariant to bold styles, or to remove
* bold from a mathvariant.
*/
public static BOLDVARIANTS: {[name: string]: StringMap} = {
bold: {
normal: 'bold',
italic: 'bold-italic',
fraktur: 'bold-fraktur',
script: 'bold-script',
'sans-serif': 'bold-sans-serif',
'sans-serif-italic': 'sans-serif-bold-italic'
},
normal: {
bold: 'normal',
'bold-italic': 'italic',
'bold-fraktur': 'fraktur',
'bold-script': 'script',
'bold-sans-serif': 'sans-serif',
'sans-serif-bold-italic': 'sans-serif-italic'
}
};
/**
* The translation of mathvariant to italic styles, or to remove
* italic from a mathvariant.
*/
public static ITALICVARIANTS: {[name: string]: StringMap} = {
italic: {
normal: 'italic',
bold: 'bold-italic',
'sans-serif': 'sans-serif-italic',
'bold-sans-serif': 'sans-serif-bold-italic'
},
normal: {
italic: 'normal',
'bold-italic': 'bold',
'sans-serif-italic': 'sans-serif',
'sans-serif-bold-italic': 'bold-sans-serif'
}
};
/**
* The factory used to create more wrappers
*/
protected factory: CommonWrapperFactory<J, W, C, CC, DD, FD>;
/**
* The parent of this node
*/
public parent: W = null;
/**
* The children of this node
*/
public childNodes: W[];
/**
* Styles that must be handled directly by the wrappers (mostly having to do with fonts)
*/
protected removedStyles: StringMap = null;
/**
* The explicit styles set by the node
*/
protected styles: Styles = null;
/**
* The mathvariant for this node
*/
public variant: string = '';
/**
* The bounding box for this node
*/
public bbox: BBox;
/**
* Whether the bounding box has been computed yet
*/
protected bboxComputed: boolean = false;
/**
* Delimiter data for stretching this node (NOSTRETCH means not yet determined)
*/
public stretch: DD = NOSTRETCH as DD;
/**
* Easy access to the font parameters
*/
public font: FD = null;
/**
* Easy access to the output jax for this node
*/
get jax() {
return this.factory.jax;
}
/**
* Easy access to the DOMAdaptor object
*/
get adaptor() {
return this.factory.jax.adaptor;
}
/**
* Easy access to the metric data for this node
*/
get metrics() {
return this.factory.jax.math.metrics;
}
/**
* True if children with percentage widths should be resolved by this container
*/
get fixesPWidth() {
return !this.node.notParent && !this.node.isToken;
}
/*******************************************************************/
/**
* @override
*/
constructor(factory: CommonWrapperFactory<J, W, C, CC, DD, FD>, node: MmlNode, parent: W = null) {
super(factory, node);
this.parent = parent;
this.font = factory.jax.font;
this.bbox = BBox.zero();
this.getStyles();
this.getVariant();
this.getScale();
this.getSpace();
this.childNodes = node.childNodes.map((child: MmlNode) => {
const wrapped = this.wrap(child);
if (wrapped.bbox.pwidth && (node.notParent || node.isKind('math'))) {
this.bbox.pwidth = BBox.fullWidth;
}
return wrapped;
});
}
/**
* @param {MmlNode} node The node to the wrapped
* @param {W} parent The wrapped parent node
* @return {W} The newly wrapped node
*/
public wrap(node: MmlNode, parent: W = null): W {
const wrapped = this.factory.wrap(node, parent || this);
if (parent) {
parent.childNodes.push(wrapped);
}
this.jax.nodeMap.set(node, wrapped);
return wrapped;
}
/*******************************************************************/
/**
* Return the wrapped node's bounding box, either the cached one, if it exists,
* or computed directly if not.
*
* @param {boolean} save Whether to cache the bbox or not (used for stretchy elements)
* @return {BBox} The computed bounding box
*/
public getBBox(save: boolean = true): BBox {
if (this.bboxComputed) {
return this.bbox;
}
const bbox = (save ? this.bbox : BBox.zero());
this.computeBBox(bbox);
this.bboxComputed = save;
return bbox;
}
/**
* Return the wrapped node's bounding box that includes borders and padding
*
* @param {boolean} save Whether to cache the bbox or not (used for stretchy elements)
* @return {BBox} The computed bounding box
*/
public getOuterBBox(save: boolean = true): BBox {
const bbox = this.getBBox(save);
if (!this.styles) return bbox;
const obox = new BBox();
Object.assign(obox, bbox);
for (const [name, side] of BBox.StyleAdjust) {
const x = this.styles.get(name);
if (x) {
(obox as any)[side] += this.length2em(x, 1, obox.rscale);
}
}
return obox;
}
/**
* @param {BBox} bbox The bounding box to modify (either this.bbox, or an empty one)
* @param {boolean} recompute True if we are recomputing due to changes in children that have percentage widths
*/
protected computeBBox(bbox: BBox, recompute: boolean = false) {
bbox.empty();
for (const child of this.childNodes) {
bbox.append(child.getOuterBBox());
}
bbox.clean();
if (this.fixesPWidth && this.setChildPWidths(recompute)) {
this.computeBBox(bbox, true);
}
}
/**
* Recursively resolve any percentage widths in the child nodes using the given
* container width (or the child width, if none was passed).
* Overriden for mtables in order to compute the width.
*
* @param {boolean} recompute True if we are recomputing due to changes in children
* @param {(number|null)=} w The width of the container (from which percentages are computed)
* @param {boolean=} clear True if pwidth marker is to be cleared
* @return {boolean} True if a percentage width was found
*/
public setChildPWidths(recompute: boolean, w: (number | null) = null, clear: boolean = true): boolean {
if (recompute) {
return false;
}
if (clear) {
this.bbox.pwidth = '';
}
let changed = false;
for (const child of this.childNodes) {
const cbox = child.getOuterBBox();
if (cbox.pwidth && child.setChildPWidths(recompute, w === null ? cbox.w : w, clear)) {
changed = true;
}
}
return changed;
}
/**
* Mark BBox to be computed again (e.g., when an mo has stretched)
*/
public invalidateBBox() {
if (this.bboxComputed) {
this.bboxComputed = false;
if (this.parent) {
this.parent.invalidateBBox();
}
}
}
/**
* Copy child skew and italic correction
*
* @param {BBox} bbox The bounding box to modify
*/
protected copySkewIC(bbox: BBox) {
const first = this.childNodes[0];
if (first?.bbox.sk) {
bbox.sk = first.bbox.sk;
}
if (first?.bbox.dx) {
bbox.dx = first.bbox.dx;
}
const last = this.childNodes[this.childNodes.length - 1];
if (last?.bbox.ic) {
bbox.ic = last.bbox.ic;
bbox.w += bbox.ic;
}
}
/*******************************************************************/
/**
* Add the style attribute, but remove any font-related styles
* (since these are handled separately by the variant)
*/
protected getStyles() {
const styleString = this.node.attributes.getExplicit('style') as string;
if (!styleString) return;
const style = this.styles = new Styles(styleString);
for (let i = 0, m = CommonWrapper.removeStyles.length; i < m; i++) {
const id = CommonWrapper.removeStyles[i];
if (style.get(id)) {
if (!this.removedStyles) this.removedStyles = {};
this.removedStyles[id] = style.get(id);
style.set(id, '');
}
}
}
/**
* Get the mathvariant (or construct one, if needed).
*/
protected getVariant() {
if (!this.node.isToken) return;
const attributes = this.node.attributes;
let variant = attributes.get('mathvariant') as string;
if (!attributes.getExplicit('mathvariant')) {
const values = attributes.getList('fontfamily', 'fontweight', 'fontstyle') as StringMap;
if (this.removedStyles) {
const style = this.removedStyles;
if (style.fontFamily) values.family = style.fontFamily;
if (style.fontWeight) values.weight = style.fontWeight;
if (style.fontStyle) values.style = style.fontStyle;
}
if (values.fontfamily) values.family = values.fontfamily;
if (values.fontweight) values.weight = values.fontweight;
if (values.fontstyle) values.style = values.fontstyle;
if (values.weight && values.weight.match(/^\d+$/)) {
values.weight = (parseInt(values.weight) > 600 ? 'bold' : 'normal');
}
if (values.family) {
variant = this.explicitVariant(values.family, values.weight, values.style);
} else {
if (this.node.getProperty('variantForm')) variant = '-tex-variant';
variant = (CommonWrapper.BOLDVARIANTS[values.weight] || {})[variant] || variant;
variant = (CommonWrapper.ITALICVARIANTS[values.style] || {})[variant] || variant;
}
}
this.variant = variant;
}
/**
* Set the CSS for a token element having an explicit font (rather than regular mathvariant).
*
* @param {string} fontFamily The font family to use
* @param {string} fontWeight The font weight to use
* @param {string} fontStyle The font style to use
*/
protected explicitVariant(fontFamily: string, fontWeight: string, fontStyle: string) {
let style = this.styles;
if (!style) style = this.styles = new Styles();
style.set('fontFamily', fontFamily);
if (fontWeight) style.set('fontWeight', fontWeight);
if (fontStyle) style.set('fontStyle', fontStyle);
return '-explicitFont';
}
/**
* Determine the scaling factor to use for this wrapped node, and set the styles for it.
*/
protected getScale() {
let scale = 1, parent = this.parent;
let pscale = (parent ? parent.bbox.scale : 1);
let attributes = this.node.attributes;
let scriptlevel = Math.min(attributes.get('scriptlevel') as number, 2);
let fontsize = attributes.get('fontsize');
let mathsize = (this.node.isToken || this.node.isKind('mstyle') ?
attributes.get('mathsize') : attributes.getInherited('mathsize'));
//
// If scriptsize is non-zero, set scale based on scriptsizemultiplier
//
if (scriptlevel !== 0) {
scale = Math.pow(attributes.get('scriptsizemultiplier') as number, scriptlevel);
let scriptminsize = this.length2em(attributes.get('scriptminsize'), .8, 1);
if (scale < scriptminsize) scale = scriptminsize;
}
//
// If there is style="font-size:...", and not fontsize attribute, use that as fontsize
//
if (this.removedStyles && this.removedStyles.fontSize && !fontsize) {
fontsize = this.removedStyles.fontSize;
}
//
// If there is a fontsize and no mathsize attribute, is that
//
if (fontsize && !attributes.getExplicit('mathsize')) {
mathsize = fontsize;
}
//
// Incorporate the mathsize, if any
//
if (mathsize !== '1') {
scale *= this.length2em(mathsize, 1, 1);
}
//
// Record the scaling factors and set the element's CSS
//
this.bbox.scale = scale;
this.bbox.rscale = scale / pscale;
}
/**
* Sets the spacing based on TeX or MathML algorithm
*/
protected getSpace() {
const isTop = this.isTopEmbellished();
const hasSpacing = this.node.hasSpacingAttributes();
if (this.jax.options.mathmlSpacing || hasSpacing) {
isTop && this.getMathMLSpacing();
} else {
this.getTeXSpacing(isTop, hasSpacing);
}
}
/**
* Get the spacing using MathML rules based on the core MO
*/
protected getMathMLSpacing() {
const node = this.node.coreMO() as MmlMo;
//
// If the mo is not within a multi-node mrow, don't add space
//
const child = node.coreParent();
const parent = child.parent;
if (!parent || !parent.isKind('mrow') || parent.childNodes.length === 1) return;
//
// Get the lspace and rspace
//
const attributes = node.attributes;
const isScript = (attributes.get('scriptlevel') > 0);
this.bbox.L = (attributes.isSet('lspace') ?
Math.max(0, this.length2em(attributes.get('lspace'))) :
MathMLSpace(isScript, node.lspace));
this.bbox.R = (attributes.isSet('rspace') ?
Math.max(0, this.length2em(attributes.get('rspace'))) :
MathMLSpace(isScript, node.rspace));
//
// If there are two adjacent <mo>, use enough left space to make it
// the maximum of the rspace of the first and lspace of the second
//
const n = parent.childIndex(child);
if (n === 0) return;
const prev = parent.childNodes[n - 1] as AbstractMmlNode;
if (!prev.isEmbellished) return;
const bbox = this.jax.nodeMap.get(prev).getBBox();
if (bbox.R) {
this.bbox.L = Math.max(0, this.bbox.L - bbox.R);
}
}
/**
* Get the spacing using the TeX rules
*
* @parm {boolean} isTop True when this is a top-level embellished operator
* @parm {boolean} hasSpacing True when there is an explicit or inherited 'form' attribute
*/
protected getTeXSpacing(isTop: boolean, hasSpacing: boolean) {
if (!hasSpacing) {
const space = this.node.texSpacing();
if (space) {
this.bbox.L = this.length2em(space);
}
}
if (isTop || hasSpacing) {
const attributes = this.node.coreMO().attributes;
if (attributes.isSet('lspace')) {
this.bbox.L = Math.max(0, this.length2em(attributes.get('lspace')));
}
if (attributes.isSet('rspace')) {
this.bbox.R = Math.max(0, this.length2em(attributes.get('rspace')));
}
}
}
/**
* @return {boolean} True if this is the top-most container of an embellished operator that is
* itself an embellished operator (the maximal embellished operator for its core)
*/
protected isTopEmbellished(): boolean {
return (this.node.isEmbellished &&
!(this.node.parent && this.node.parent.isEmbellished));
}
/*******************************************************************/
/**
* @return {CommonWrapper} The wrapper for this node's core node
*/
public core(): CommonWrapper<J, W, C, CC, DD, FD> {
return this.jax.nodeMap.get(this.node.core());
}
/**
* @return {CommonWrapper} The wrapper for this node's core <mo> node
*/
public coreMO(): CommonWrapper<J, W, C, CC, DD, FD> {
return this.jax.nodeMap.get(this.node.coreMO());
}
/**
* @return {string} For a token node, the combined text content of the node's children
*/
public getText(): string {
let text = '';
if (this.node.isToken) {
for (const child of this.node.childNodes) {
if (child instanceof TextNode) {
text += child.getText();
}
}
}
return text;
}
/**
* @param {DIRECTION} direction The direction to stretch this node
* @return {boolean} Whether the node can stretch in that direction
*/
public canStretch(direction: DIRECTION): boolean {
this.stretch = NOSTRETCH as DD;
if (this.node.isEmbellished) {
let core = this.core();
if (core && core.node !== this.node) {
if (core.canStretch(direction)) {
this.stretch = core.stretch;
}
}
}
return this.stretch.dir !== DIRECTION.None;
}
/**
* @return {[string, number]} The alignment and indentation shift for the expression
*/
protected getAlignShift(): [string, number] {
let {indentalign, indentshift, indentalignfirst, indentshiftfirst} =
this.node.attributes.getList(...indentAttributes) as StringMap;
if (indentalignfirst !== 'indentalign') {
indentalign = indentalignfirst;
}
if (indentalign === 'auto') {
indentalign = this.jax.options.displayAlign;
}
if (indentshiftfirst !== 'indentshift') {
indentshift = indentshiftfirst;
}
if (indentshift === 'auto') {
indentshift = this.jax.options.displayIndent;
if (indentalign === 'right' && !indentshift.match(/^\s*0[a-z]*\s*$/)) {
indentshift = ('-' + indentshift.trim()).replace(/^--/, '');
}
}
const shift = this.length2em(indentshift, this.metrics.containerWidth);
return [indentalign, shift] as [string, number];
}
/**
* @param {number} W The total width
* @param {BBox} bbox The bbox to be aligned
* @param {string} align How to align (left, center, right)
* @return {number} The x position of the aligned width
*/
protected getAlignX(W: number, bbox: BBox, align: string): number {
return (align === 'right' ? W - (bbox.w + bbox.R) * bbox.rscale :
align === 'left' ? bbox.L * bbox.rscale :
(W - bbox.w * bbox.rscale) / 2);
}
/**
* @param {number} H The total height
* @param {number} D The total depth
* @param {number} h The height to be aligned
* @param {number} d The depth to be aligned
* @param {string} align How to align (top, bottom, center, axis, baseline)
* @return {number} The y position of the aligned baseline
*/
protected getAlignY(H: number, D: number, h: number, d: number, align: string): number {
return (align === 'top' ? H - h :
align === 'bottom' ? d - D :
align === 'center' ? ((H - h) - (D - d)) / 2 :
0); // baseline and axis
}
/**
* @param {number} i The index of the child element whose container is needed
* @return {number} The inner width as a container (for percentage widths)
*/
public getWrapWidth(i: number): number {
return this.childNodes[i].getBBox().w;
}
/**
* @param {number} i The index of the child element whose container is needed
* @return {string} The alignment child element
*/
public getChildAlign(_i: number): string {
return 'left';
}
/*******************************************************************/
/*
* Easy access to some utility routines
*/
/**
* @param {number} m A number to be shown as a percent
* @return {string} The number m as a percent
*/
protected percent(m: number): string {
return LENGTHS.percent(m);
}
/**
* @param {number} m A number to be shown in ems
* @return {string} The number with units of ems
*/
protected em(m: number): string {
return LENGTHS.em(m);
}
/**
* @param {number} m A number of em's to be shown as pixels
* @param {number} M The minimum number of pixels to allow
* @return {string} The number with units of px
*/
protected px(m: number, M: number = -LENGTHS.BIGDIMEN): string {
return LENGTHS.px(m, M, this.metrics.em);
}
/**
* @param {Property} length A dimension (giving number and units) or number to be converted to ems
* @param {number} size The default size of the dimension (for percentage values)
* @param {number} scale The current scaling factor (to handle absolute units)
* @return {number} The dimension converted to ems
*/
protected length2em(length: Property, size: number = 1, scale: number = null): number {
if (scale === null) {
scale = this.bbox.scale;
}
return LENGTHS.length2em(length as string, size, scale, this.jax.pxPerEm);
}
/**
* @param {string} text The text to turn into unicode locations
* @param {string} name The name of the variant for the characters
* @return {number[]} Array of numbers represeting the string's unicode character positions
*/
protected unicodeChars(text: string, name: string = this.variant): number[] {
let chars = unicodeChars(text);
//
// Remap to Math Alphanumerics block
//
const variant = this.font.getVariant(name);
if (variant && variant.chars) {
const map = variant.chars;
//
// Is map[n] doesn't exist, (map[n] || []) still gives an CharData array.
// If the array doesn't have a CharOptions element use {} instead.
// Then check if the options has an smp property, which gives
// the Math Alphabet mapping for this character.
// Otherwise use the original code point, n.
//
chars = chars.map((n) => ((map[n] || [])[3] || {}).smp || n);
}
return chars;
}
/**
* @param {number[]} chars The array of unicode character numbers to remap
* @return {number[]} The converted array
*/
public remapChars(chars: number[]): number[] {
return chars;
}
/**
* @param {string} text The text from which to create a TextNode object
* @return {TextNode} The TextNode with the given text
*/
public mmlText(text: string): TextNode {
return ((this.node as AbstractMmlNode).factory.create('text') as TextNode).setText(text);
}
/**
* @param {string} kind The kind of MmlNode to create
* @param {ProperyList} properties The properties to set initially
* @param {MmlNode[]} children The child nodes to add to the created node
* @return {MmlNode} The newly created MmlNode
*/
public mmlNode(kind: string, properties: PropertyList = {}, children: MmlNode[] = []): MmlNode {
return (this.node as AbstractMmlNode).factory.create(kind, properties, children);
}
/**
* Create an mo wrapper with the given text,
* link it in, and give it the right defaults.
*
* @param {string} text The text for the wrapped element
* @return {CommonWrapper} The wrapped MmlMo node
*/
protected createMo(text: string): CommonWrapper<J, W, C, CC, DD, FD> {
const mmlFactory = (this.node as AbstractMmlNode).factory;
const textNode = (mmlFactory.create('text') as TextNode).setText(text);
const mml = mmlFactory.create('mo', {stretchy: true}, [textNode]);
mml.inheritAttributesFrom(this.node);
const node = this.wrap(mml);
node.parent = this as any as W;
return node;
}
/**
* @param {string} variant The variant in which to look for the character
* @param {number} n The number of the character to look up
* @return {CharData} The full CharData object, with CharOptions guaranteed to be defined
*/
protected getVariantChar(variant: string, n: number): CharData<CC> {
const char = this.font.getChar(variant, n) || [0, 0, 0, {unknown: true} as CC];
if (char.length === 3) {
(char as any)[3] = {};
}
return char as [number, number, number, CC];
}
}
+69
View File
@@ -0,0 +1,69 @@
/*************************************************************
*
* Copyright (c) 2017-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview Implements the OutputWrapperFactory class
*
* @author dpvc@mathjax.org (Davide Cervone)
*/
import {CommonOutputJax} from './OutputJax.js';
import {AbstractWrapperFactory} from '../../core/Tree/WrapperFactory.js';
import {CommonWrapper, CommonWrapperClass} from './Wrapper.js';
import {CharOptions, DelimiterData, FontData} from './FontData.js';
import {MmlNode} from '../../core/MmlTree/MmlNode.js';
/*****************************************************************/
/**
* The OutputWrapperFactory class for creating OutputWrapper nodes
*
* @template J The OutputJax type
* @template W The Wrapper type
* @template C The WrapperClass type
* @template CC The CharOptions type
* @template FD The FontData type
*/
export class CommonWrapperFactory<
J extends CommonOutputJax<any, any, any, W, CommonWrapperFactory<J, W, C, CC, DD, FD>, FD, any>,
W extends CommonWrapper<J, W, C, CC, DD, FD>,
C extends CommonWrapperClass<J, W, C, CC, DD, FD>,
CC extends CharOptions,
DD extends DelimiterData,
FD extends FontData<CC, any, DD>
> extends AbstractWrapperFactory<MmlNode, W, C> {
/**
* The default list of wrapper nodes this factory can create
* (filled in by subclasses)
*/
public static defaultNodes: {[kind: string]: CommonWrapperClass<any, any, any, any, any, any>} = {};
/**
* The output jax associated with this factory
*/
public jax: J = null;
/**
* @return {Object} The list of node-creation functions
*/
get Wrappers(): Object {
return this.node;
}
}
export type AnyWrapperFactory = CommonWrapperFactory<any, any, any, any, any, any>;
+72
View File
@@ -0,0 +1,72 @@
/*************************************************************
*
* Copyright (c) 2017-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview Implements the CommonTeXAtom wrapper mixin for the MmlTeXAtom object
*
* @author dpvc@mathjax.org (Davide Cervone)
*/
import {AnyWrapper, WrapperConstructor, Constructor} from '../Wrapper.js';
import {BBox} from '../../../util/BBox.js';
import {TEXCLASS} from '../../../core/MmlTree/MmlNode.js';
/*****************************************************************/
/**
* The CommonTeXAtom interface
*/
export interface CommonTeXAtom extends AnyWrapper {
}
/**
* Shorthand for the CommonTeXAtom constructor
*/
export type TeXAtomConstructor = Constructor<CommonTeXAtom>;
/*****************************************************************/
/**
* The CommonTeXAtom wrapper mixin for the TeXAtom object
*
* @template T The Wrapper class constructor type
*/
export function CommonTeXAtomMixin<T extends WrapperConstructor>(Base: T): TeXAtomConstructor & T {
return class extends Base {
/**
* @override
*/
public computeBBox(bbox: BBox, recompute: boolean = false) {
super.computeBBox(bbox, recompute);
if (this.childNodes[0] && this.childNodes[0].bbox.ic) {
bbox.ic = this.childNodes[0].bbox.ic;
}
//
// Center VCENTER atoms vertically
//
if (this.node.texClass === TEXCLASS.VCENTER) {
const {h, d} = bbox;
const a = this.font.params.axis_height;
const dh = ((h + d) / 2 + a) - h; // new height minus old height
bbox.h += dh;
bbox.d -= dh;
}
}
};
}
+143
View File
@@ -0,0 +1,143 @@
/*************************************************************
*
* Copyright (c) 2017-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview Implements the CommonTextNode wrapper mixin for the TextNode object
*
* @author dpvc@mathjax.org (Davide Cervone)
*/
import {AnyWrapper, WrapperConstructor, Constructor} from '../Wrapper.js';
import {BBox} from '../../../util/BBox.js';
import {TextNode} from '../../../core/MmlTree/MmlNode.js';
/*****************************************************************/
/**
* The CommonTextNode interface
*/
export interface CommonTextNode extends AnyWrapper {
/**
* @param {string} text The text to remap
* @param {string} variant The variant for the character
* @return {number[]} The unicode points for the (remapped) text
*/
remappedText(text: string, variant: string): number[];
}
/**
* Shorthand for the CommonTextNode constructor
*/
export type TextNodeConstructor = Constructor<CommonTextNode>;
/*****************************************************************/
/**
* The CommonTextNode wrapper mixin for the TextNode object
*
* @template T The Wrapper class constructor type
*/
export function CommonTextNodeMixin<T extends WrapperConstructor>(Base: T): TextNodeConstructor & T {
return class extends Base {
/**
* @override
*/
public computeBBox(bbox: BBox, _recompute: boolean = false) {
const variant = this.parent.variant;
const text = (this.node as TextNode).getText();
if (variant === '-explicitFont') {
//
// Measure the size of the text (using the DOM if possible)
//
const font = this.jax.getFontData(this.parent.styles);
const {w, h, d} = this.jax.measureText(text, variant, font);
bbox.h = h;
bbox.d = d;
bbox.w = w;
} else {
const chars = this.remappedText(text, variant);
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) {
//
// Measure unknown characters using the DOM (if possible)
//
const cbox = this.jax.measureText(String.fromCodePoint(char), variant);
w = cbox.w;
h = cbox.h;
d = cbox.d;
}
//
// 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;
}
if (chars.length > 1) {
bbox.sk = 0;
}
bbox.clean();
}
}
/**
* @param {string} text The text to remap
* @param {string} variant The variant for the character
* @return {number[]} The unicode points for the (remapped) text
*/
public remappedText(text: string, variant: string): number[] {
const c = this.parent.stretch.c;
return (c ? [c] : this.parent.remapChars(this.unicodeChars(text, variant)));
}
/******************************************************/
/*
* TextNodes don't need these, since these properties
* are inherited from the parent nodes
*/
/**
* @override
*/
public getStyles() {}
/**
* @override
*/
public getVariant() {}
/**
* @override
*/
public getScale() {}
/**
* @override
*/
public getSpace() {}
};
}
+193
View File
@@ -0,0 +1,193 @@
/*************************************************************
*
* Copyright (c) 2018-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview Implements the CommonMaction wrapper mixin for the MmlMaction object
*
* @author dpvc@mathjax.org (Davide Cervone)
*/
import {AnyWrapper, WrapperConstructor, Constructor, AnyWrapperClass} from '../Wrapper.js';
import {MmlMaction} from '../../../core/MmlTree/MmlNodes/maction.js';
import {BBox} from '../../../util/BBox.js';
import {split} from '../../../util/string.js';
/*****************************************************************/
/**
* The types needed to define the actiontypes
*
* @template W The maction wrapper type
*/
export type ActionData = {[name: string]: any};
export type ActionHandler<W extends AnyWrapper> = (node: W, data?: ActionData) => void;
export type ActionPair<W extends AnyWrapper> = [ActionHandler<W>, ActionData];
export type ActionMap<W extends AnyWrapper> = Map<string, ActionPair<W>>;
export type ActionDef<W extends AnyWrapper> = [string, [ActionHandler<W>, ActionData]];
export type EventHandler = (event: Event) => void;
/**
* Data used for tooltip actions
*/
export const TooltipData = {
dx: '.2em', // x-offset of tooltip from right side of maction bbox
dy: '.1em', // y-offset of tooltip from bottom of maction bbox
postDelay: 600, // milliseconds before tooltip posts
clearDelay: 100, // milliseconds before tooltip is removed
hoverTimer: new Map<any, number>(), // timers for posting tooltips
clearTimer: new Map<any, number>(), // timers for removing tooltips
/*
* clear the timers if any are active
*/
stopTimers: (node: any, data: ActionData) => {
if (data.clearTimer.has(node)) {
clearTimeout(data.clearTimer.get(node));
data.clearTimer.delete(node);
}
if (data.hoverTimer.has(node)) {
clearTimeout(data.hoverTimer.get(node));
data.hoverTimer.delete(node);
}
}
};
/*****************************************************************/
/**
* The CommonMaction interface
*
* @template W The maction wrapper type
*/
export interface CommonMaction<W extends AnyWrapper> extends AnyWrapper {
/**
* The handler for the specified actiontype
*/
action: ActionHandler<W>;
data: ActionData;
/**
* Tooltip offsets
*/
dx: number;
dy: number;
/**
* The selected child wrapper
*/
readonly selected: W;
}
/**
* The CommonMaction class interface
*
* @template W The maction wrapper type
*/
export interface CommonMactionClass<W extends AnyWrapper> extends AnyWrapperClass {
/**
* The valid action types and their handlers
*/
actions: ActionMap<W>;
}
/**
* Shorthand for the CommonMaction constructor
*
* @template W The maction wrapper type
*/
export type MactionConstructor<W extends AnyWrapper> = Constructor<CommonMaction<W>>;
/*****************************************************************/
/**
* The CommonMaction wrapper mixin for the MmlMaction object
*
* @template W The maction wrapper type
* @template T The Wrapper class constructor type
*/
export function CommonMactionMixin<
W extends AnyWrapper,
T extends WrapperConstructor
>(Base: T): MactionConstructor<W> & T {
return class extends Base {
/**
* The handler for the specified actiontype
*/
public action: ActionHandler<W>;
/**
* The data for the specified actiontype
*/
public data: ActionData;
/**
* The x-offset for tooltips
*/
public dx: number;
/**
* The y-offset for tooltips
*/
public dy: number;
/**
* @return {W} The selected child wrapper
*/
public get selected(): W {
const selection = this.node.attributes.get('selection') as number;
const i = Math.max(1, Math.min(this.childNodes.length, selection)) - 1;
return this.childNodes[i] || this.wrap((this.node as MmlMaction).selected);
}
/*************************************************************/
/**
* @override
*/
constructor(...args: any[]) {
super(...args);
const actions = (this.constructor as CommonMactionClass<W>).actions;
const action = this.node.attributes.get('actiontype') as string;
const [handler, data] = actions.get(action) || [((_node, _data) => {}) as ActionHandler<W>, {}];
this.action = handler;
this.data = data;
this.getParameters();
}
/**
* Look up attribute parameters
*/
public getParameters() {
const offsets = this.node.attributes.get('data-offsets') as string;
let [dx, dy] = split(offsets || '');
this.dx = this.length2em(dx || TooltipData.dx);
this.dy = this.length2em(dy || TooltipData.dy);
}
/**
* @override
*/
public computeBBox(bbox: BBox, recompute: boolean = false) {
bbox.updateFrom(this.selected.getOuterBBox());
this.selected.setChildPWidths(recompute);
}
};
}
+57
View File
@@ -0,0 +1,57 @@
/*************************************************************
*
* Copyright (c) 2018-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview Implements the CommonMath wrapper mixin for the MmlMath object
*
* @author dpvc@mathjax.org (Davide Cervone)
*/
import {AnyWrapper, WrapperConstructor, Constructor} from '../Wrapper.js';
/*****************************************************************/
/**
* The CommonMath interface
*/
export interface CommonMath extends AnyWrapper {
}
/**
* Shorthand for the CommonMath constructor
*/
export type MathConstructor = Constructor<CommonMath>;
/*****************************************************************/
/**
* The CommonMath wrapper mixin for the MmlMath object
*
* @template T The Wrapper class constructor type
*/
export function CommonMathMixin<T extends WrapperConstructor>(Base: T): MathConstructor & T {
return class extends Base {
/**
* @override
*/
public getWrapWidth(_i: number) {
return (this.parent ? this.getBBox().w : this.metrics.containerWidth / this.jax.pxPerEm);
}
};
}
+465
View File
@@ -0,0 +1,465 @@
/*************************************************************
*
* Copyright (c) 2018-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview Implements the CommonMenclose wrapper mixin for the MmlMenclose object
*
* @author dpvc@mathjax.org (Davide Cervone)
*/
import {AnyWrapper, WrapperConstructor, Constructor, AnyWrapperClass} from '../Wrapper.js';
import * as Notation from '../Notation.js';
import {CommonMsqrt} from './msqrt.js';
import {BBox} from '../../../util/BBox.js';
import {AbstractMmlNode} from '../../../core/MmlTree/MmlNode.js';
import {split} from '../../../util/string.js';
/*****************************************************************/
/**
* The CommonMenclose interface
*
* @template W The menclose wrapper type
*/
export interface CommonMenclose<W extends AnyWrapper, S extends CommonMsqrt, N> extends AnyWrapper {
/**
* The notations active on this menclose, and the one to use for the child, if any
*/
notations: Notation.List<W, N>;
renderChild: Notation.Renderer<W, N>;
/**
* fake msqrt for radial notation (if used)
*/
msqrt: S;
/**
* The padding, thickness, and shape of the arrow head
* (may be overridden using data-padding, data-thickness, and data-arrowhead attibutes)
*/
padding: number;
thickness: number;
arrowhead: {x: number, y: number, dx: number};
/**
* The top, right, bottom, and left padding, added by notations
*/
TRBL: Notation.PaddingData;
/**
* Look up the data-* attributes and override the default values
*/
getParameters(): void;
/**
* Get the notations given in the notation attribute
* and check if any are used to render the child nodes
*/
getNotations(): void;
/**
* Remove any redundant notations
*/
removeRedundantNotations(): void;
/**
* Run any initialization needed by notations in use
*/
initializeNotations(): void;
/**
* @return {Notation.PaddingData} Array of the maximum extra space from the notations along each side
*/
getBBoxExtenders(): Notation.PaddingData;
/**
* @return {Notation.PaddingData} Array of padding (i.e., BBox minus border) along each side
*/
getPadding(): Notation.PaddingData;
/**
* Each entry in X gets replaced by the corresponding one in Y if it is larger
*
* @param {Notation.PaddingData} X An array of numbers
* @param {Notation.PaddingData} Y An array of numbers that replace smaller ones in X
*/
maximizeEntries(X: Notation.PaddingData, Y: Notation.PaddingData): void;
/**
* Get the offset amount for the given direction for vertical and horizontal centering
*
* @param {string} direction The direction 'X' or 'Y' for the offset
* @return {number} The amount of offset in that direction
*/
getOffset(direction: string): number;
/**
* @param {number} w The width of the box whose diagonal is needed
* @param {number} h The height of the box whose diagonal is needed
* @return {number[]} The angle and width of the diagonal of the box
*/
getArgMod(w: number, h: number): [number, number];
/**
* Create an arrow for output
*
* @param {number} w The length of the arrow
* @param {number} a The angle for the arrow
* @param {boolean} double True if this is a double-headed arrow
* @param {string} offset 'X' for vertical arrow, 'Y' for horizontal
* @param {number} trans Distance to translate in the offset direction
* @return {N} The newly created arrow
*/
arrow(w: number, a: number, double: boolean, offset?: string, trans?: number): N;
/**
* Get the angle and width of a diagonal arrow, plus the x and y extension
* past the content bounding box
*/
arrowData(): {a: number, W: number, x: number, y: number};
/**
* Get the angle and width for a diagonal arrow
*
* @return {[number, number]} The angle and width
*/
arrowAW(): [number, number];
/**
* Create an unattached msqrt wrapper to render the 'radical' notation.
* We replace the inferred mrow of the msqrt with the one from the menclose
* but without changing the parent pointer, so as not to detach it from
* the menclose (which would desrtoy the original MathML tree).
*
* @param {W} child The inferred mrow that is the child of this menclose
* @return {S} The newly created (but detached) msqrt wrapper
*/
createMsqrt(child: W): S;
/**
* @return {number[]} The differences between the msqrt bounding box
* and its child bounding box (i.e., the extra space
* created by the radical symbol).
*/
sqrtTRBL(): number[];
}
/**
* The CommonMenclose class interface
*
* @template W The menclose wrapper type
* @templare N The DOM node class
*/
export interface CommonMencloseClass<W extends AnyWrapper, N> extends AnyWrapperClass {
/**
* The definitions of the various notations
*/
notations: Notation.DefList<W, N>;
}
/**
* Shorthand for the CommonMenclose constructor
*
* @template W The menclose wrapper type
*/
export type MencloseConstructor<W extends AnyWrapper, S extends CommonMsqrt, N> = Constructor<CommonMenclose<W, S, N>>;
/*****************************************************************/
/**
* The CommonMenclose wrapper mixin for the MmlMenclose object
*
* @template W The menclose wrapper type
* @templare N The DOM node class
* @templare S The msqrt wrapper class
* @template T The Wrapper class constructor type
*/
export function CommonMencloseMixin<
W extends AnyWrapper,
S extends CommonMsqrt,
N,
T extends WrapperConstructor
>(Base: T): MencloseConstructor<W, S, N> & T {
return class extends Base {
/**
* The notations active on this menclose, if any
*/
public notations: Notation.List<W, N> = {};
/**
* The notation to use for the child, if any
*/
public renderChild: Notation.Renderer<W, N> = null;
/**
* fake msqrt for radial notation (if used)
*/
public msqrt: S = null;
/**
* The padding of the arrow head (may be overridden using data-padding attibute)
*/
public padding: number = Notation.PADDING;
/**
* The thickness of the arrow head (may be overridden using data-thickness attibute)
*/
public thickness: number = Notation.THICKNESS;
/**
* The shape of the arrow head (may be overridden using data-arrowhead attibutes)
*/
public arrowhead = {x: Notation.ARROWX, y: Notation.ARROWY, dx: Notation.ARROWDX};
/**
* The top, right, bottom, and left padding (added by notations)
*/
public TRBL: Notation.PaddingData = [0, 0, 0, 0];
/**
* @override
* @constructor
*/
constructor(...args: any[]) {
super(...args);
this.getParameters();
this.getNotations();
this.removeRedundantNotations();
this.initializeNotations();
this.TRBL = this.getBBoxExtenders();
}
/**
* Look up the data-* attributes and override the default values
*/
public getParameters() {
const attributes = this.node.attributes;
const padding = attributes.get('data-padding');
if (padding !== undefined) {
this.padding = this.length2em(padding, Notation.PADDING);
}
const thickness = attributes.get('data-thickness');
if (thickness !== undefined) {
this.thickness = this.length2em(thickness, Notation.THICKNESS);
}
const arrowhead = attributes.get('data-arrowhead') as string;
if (arrowhead !== undefined) {
let [x, y, dx] = split(arrowhead);
this.arrowhead = {
x: (x ? parseFloat(x) : Notation.ARROWX),
y: (y ? parseFloat(y) : Notation.ARROWY),
dx: (dx ? parseFloat(dx) : Notation.ARROWDX)
};
}
}
/**
* Get the notations given in the notation attribute
* and check if any are used to render the child nodes
*/
public getNotations() {
const Notations = (this.constructor as CommonMencloseClass<W, N>).notations;
for (const name of split(this.node.attributes.get('notation') as string)) {
const notation = Notations.get(name);
if (notation) {
this.notations[name] = notation;
if (notation.renderChild) {
this.renderChild = notation.renderer;
}
}
}
}
/**
* Remove any redundant notations
*/
public removeRedundantNotations() {
for (const name of Object.keys(this.notations)) {
if (this.notations[name]) {
const remove = this.notations[name].remove || '';
for (const notation of remove.split(/ /)) {
delete this.notations[notation];
}
}
}
}
/**
* Run any initialization needed by notations in use
*/
public initializeNotations() {
for (const name of Object.keys(this.notations)) {
const init = this.notations[name].init;
init && init(this as any);
}
}
/********************************************************/
/**
* @override
*/
public computeBBox(bbox: BBox, recompute: boolean = false) {
//
// Combine the BBox from the child and add the extenders
//
let [T, R, B, L] = this.TRBL;
const child = this.childNodes[0].getBBox();
bbox.combine(child, L, 0);
bbox.h += T;
bbox.d += B;
bbox.w += R;
this.setChildPWidths(recompute);
}
/**
* @return {Notation.PaddingData} Array of the maximum extra space from the notations along each side
*/
public getBBoxExtenders(): Notation.PaddingData {
let TRBL = [0, 0, 0, 0] as Notation.PaddingData;
for (const name of Object.keys(this.notations)) {
this.maximizeEntries(TRBL, this.notations[name].bbox(this as any));
}
return TRBL;
}
/**
* @return {Notation.PaddingData} Array of padding (i.e., BBox minus border) along each side
*/
public getPadding(): Notation.PaddingData {
let BTRBL = [0, 0, 0, 0] as Notation.PaddingData;
for (const name of Object.keys(this.notations)) {
const border = this.notations[name].border;
if (border) {
this.maximizeEntries(BTRBL, border(this as any));
}
}
return [0, 1, 2, 3].map(i => this.TRBL[i] - BTRBL[i]) as Notation.PaddingData;
}
/**
* Each entry in X gets replaced by the corresponding one in Y if it is larger
*
* @param {Notation.PaddingData} X An array of numbers
* @param {Notation.PaddingData} Y An array of numbers that replace smaller ones in X
*/
public maximizeEntries(X: Notation.PaddingData, Y: Notation.PaddingData) {
for (let i = 0; i < X.length; i++) {
if (X[i] < Y[i]) {
X[i] = Y[i];
}
}
}
/********************************************************/
/**
* Get the offset amount for the given direction for vertical and horizontal centering
*
* @param {string} direction The direction 'X' or 'Y' for the offset
* @return {number} The amount of offset in that direction
*/
public getOffset(direction: string): number {
let [T, R, B, L] = this.TRBL;
const d = (direction === 'X' ? R - L : B - T) / 2;
return (Math.abs(d) > .001 ? d : 0);
}
/**
* @param {number} w The width of the box whose diagonal is needed
* @param {number} h The height of the box whose diagonal is needed
* @return {number[]} The angle and width of the diagonal of the box
*/
public getArgMod(w: number, h: number): [number, number] {
return [Math.atan2(h, w), Math.sqrt(w * w + h * h)];
}
/**
* Create an arrow using an svg element
*
* @param {number} w The length of the arrow
* @param {number} a The angle for the arrow
* @param {boolean} double True if this is a double-headed arrow
* @param {string} offset 'X' for vertical arrow, 'Y' for horizontal
* @param {number} dist Distance to translate in the offset direction
* @return {N} The newly created arrow
*/
public arrow(_w: number, _a: number, _double: boolean, _offset: string = '', _dist: number = 0): N {
return null as N;
}
/**
* Get the angle and width of a diagonal arrow, plus the x and y extension
* past the content bounding box
*
* @return {Object} The angle, width, and x and y extentions
*/
public arrowData(): {a: number, W: number, x: number, y: number} {
const [p, t] = [this.padding, this.thickness];
const r = t * (this.arrowhead.x + Math.max(1, this.arrowhead.dx));
const {h, d, w} = this.childNodes[0].getBBox();
const H = h + d;
const R = Math.sqrt(H * H + w * w);
const x = Math.max(p, r * w / R);
const y = Math.max(p, r * H / R);
const [a, W] = this.getArgMod(w + 2 * x, H + 2 * y);
return {a, W, x, y};
}
/**
* Get the angle and width for a diagonal arrow
*
* @return {[number, number]} The angle and width
*/
public arrowAW(): [number, number] {
const {h, d, w} = this.childNodes[0].getBBox();
const [T, R, B, L] = this.TRBL;
return this.getArgMod(L + w + R, T + h + d + B);
}
/********************************************************/
/**
* Create an unattached msqrt wrapper to render the 'radical' notation.
* We replace the inferred mrow of the msqrt with the one from the menclose
* but without changing the parent pointer, so as not to detach it from
* the menclose (which would desrtoy the original MathML tree).
*
* @param {W} child The inferred mrow that is the child of this menclose
* @return {S} The newly created (but detached) msqrt wrapper
*/
public createMsqrt(child: W): S {
const mmlFactory = (this.node as AbstractMmlNode).factory;
const mml = mmlFactory.create('msqrt');
mml.inheritAttributesFrom(this.node);
mml.childNodes[0] = child.node;
const node = this.wrap(mml) as S;
node.parent = this;
return node;
}
/**
* @return {number[]} The differences between the msqrt bounding box
* and its child bounding box (i.e., the extra space
* created by the radical symbol).
*/
public sqrtTRBL(): [number, number, number, number] {
const bbox = this.msqrt.getBBox();
const cbox = this.msqrt.childNodes[0].getBBox();
return [bbox.h - cbox.h, 0, bbox.d - cbox.d, bbox.w - cbox.w];
}
};
}
+144
View File
@@ -0,0 +1,144 @@
/*************************************************************
*
* Copyright (c) 2018-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview Implements the CommonMfenced wrapper mixin for the MmlMfenced object
*
* @author dpvc@mathjax.org (Davide Cervone)
*/
import {AnyWrapper, WrapperConstructor, Constructor} from '../Wrapper.js';
import {CommonInferredMrow} from './mrow.js';
import {MmlNode, AbstractMmlNode} from '../../../core/MmlTree/MmlNode.js';
import {MmlMfenced} from '../../../core/MmlTree/MmlNodes/mfenced.js';
import {BBox} from '../../../util/BBox.js';
/*****************************************************************/
/**
* The CommonMfenced interface
*/
export interface CommonMfenced extends AnyWrapper {
/**
* An mrow to use for the layout of the mfenced
*/
mrow: CommonInferredMrow;
/**
* Creates the mrow wrapper to use for the layout
*/
createMrow(): void;
/**
* Populate the mrow with wrapped mo elements interleaved
* with the mfenced children (the mo's are already created
* in the mfenced object)
*/
addMrowChildren(): void;
/**
* Wrap an mo element and push it onto the mrow
*
* @param {MmlNode} node The mo element to push on the mrow
*/
addMo(node: MmlNode): void;
}
/**
* Shorthand for the CommonMfenced constructor
*/
export type MfencedConstructor = Constructor<CommonMfenced>;
/*****************************************************************/
/**
* The CommonMfenced wrapper mixin for the MmlMfenced object
*
* @template T The Wrapper class constructor type
*/
export function CommonMfencedMixin<T extends WrapperConstructor>(Base: T): MfencedConstructor & T {
return class extends Base {
/**
* An mrow to use for the layout of the mfenced
*/
public mrow: CommonInferredMrow = null;
/**
* @override
* @constructor
*/
constructor(...args: any[]) {
super(...args);
this.createMrow();
this.addMrowChildren();
}
/**
* Creates the mrow wrapper to use for the layout
*/
public createMrow() {
const mmlFactory = (this.node as AbstractMmlNode).factory;
const mrow = mmlFactory.create('inferredMrow');
mrow.inheritAttributesFrom(this.node);
this.mrow = this.wrap(mrow) as CommonInferredMrow;
this.mrow.parent = this;
}
/**
* Populate the mrow with wrapped mo elements interleaved
* with the mfenced children (the mo's are already created
* in the mfenced object)
*/
public addMrowChildren() {
const mfenced = this.node as MmlMfenced;
const mrow = this.mrow;
this.addMo(mfenced.open);
if (this.childNodes.length) {
mrow.childNodes.push(this.childNodes[0]);
}
let i = 0;
for (const child of this.childNodes.slice(1)) {
this.addMo(mfenced.separators[i++]);
mrow.childNodes.push(child);
}
this.addMo(mfenced.close);
mrow.stretchChildren();
}
/**
* Wrap an mo element and push it onto the mrow
*
* @param {MmlNode} node The mo element to push on the mrow
*/
public addMo(node: MmlNode) {
if (!node) return;
const mo = this.wrap(node);
this.mrow.childNodes.push(mo);
mo.parent = this.mrow;
}
/**
* @override
*/
public computeBBox(bbox: BBox, recompute: boolean = false) {
bbox.updateFrom(this.mrow.getOuterBBox());
this.setChildPWidths(recompute);
}
};
}
+302
View File
@@ -0,0 +1,302 @@
/*************************************************************
*
* Copyright (c) 2017-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview Implements the CommonMfrac wrapper mixin for the MmlMfrac object
*
* @author dpvc@mathjax.org (Davide Cervone)
*/
import {AnyWrapper, WrapperConstructor, Constructor} from '../Wrapper.js';
import {CommonMo} from './mo.js';
import {BBox} from '../../../util/BBox.js';
import {DIRECTION} from '../FontData.js';
/*****************************************************************/
/**
* The CommonMfrac interface
*/
export interface CommonMfrac extends AnyWrapper {
/**
* @param {BBox} bbox The buonding box to modify
* @param {boolean} display True for display-mode fractions
* @param {number} t The thickness of the line
*/
getFractionBBox(bbox: BBox, display: boolean, t: number): void;
/**
* @param {boolean} display True for display-mode fractions
* @param {number} t The thickness of the line
* @return {Object} The expanded rule thickness (T), and baseline offsets
* for numerator and denomunator (u and v)
*/
getTUV(display: boolean, t: number): {T: number, u: number, v: number};
/**
* @param {BBox} bbox The bounding box to modify
* @param {boolean} display True for display-mode fractions
*/
getAtopBBox(bbox: BBox, display: boolean): void;
/**
* @param {boolean} display True for diplay-mode fractions
* @return {Object}
* The vertical offsets of the numerator (u), the denominator (v),
* the separation between the two, and the bboxes themselves.
*/
getUVQ(display: boolean): {u: number, v: number, q: number, nbox: BBox, dbox: BBox};
/**
* @param {BBox} bbox The boundng box to modify
* @param {boolean} display True for display-mode fractions
*/
getBevelledBBox(bbox: BBox, display: boolean): void;
/**
* @param {boolean} display True for display-style fractions
* @return {Object} The height (H) of the bevel, horizontal offest (delta)
* vertical offsets (u and v) of the parts, and
* bounding boxes of the parts.
*/
getBevelData(display: boolean): {H: number, delta: number, u: number, v: number, nbox: BBox, dbox: BBox};
/**
* @return {boolean} True if in display mode, false otherwise
*/
isDisplay(): boolean;
}
/**
* Shorthand for the CommonMfrac constructor
*/
export type MfracConstructor = Constructor<CommonMfrac>;
/*****************************************************************/
/**
* The CommonMfrac wrapper mixin for the MmlMfrac object
*
* @template T The Wrapper class constructor type
*/
export function CommonMfracMixin<T extends WrapperConstructor>(Base: T): MfracConstructor & T {
return class extends Base {
/**
* Wrapper for <mo> to use for bevelled fraction
*/
public bevel: CommonMo = null;
/**
* Padding around fractions
*/
public pad: number;
/************************************************/
/**
* @override
* @constructor
*/
constructor(...args: any[]) {
super(...args);
this.pad = (this.node.getProperty('withDelims') as boolean ? 0 : this.font.params.nulldelimiterspace);
//
// create internal bevel mo element
//
if (this.node.attributes.get('bevelled')) {
const {H} = this.getBevelData(this.isDisplay());
const bevel = this.bevel = this.createMo('/') as CommonMo;
bevel.node.attributes.set('symmetric', true);
bevel.canStretch(DIRECTION.Vertical);
bevel.getStretchedVariant([H], true);
}
}
/**
* @override
*/
public computeBBox(bbox: BBox, recompute: boolean = false) {
bbox.empty();
const {linethickness, bevelled} = this.node.attributes.getList('linethickness', 'bevelled');
const display = this.isDisplay();
let w = null as (number | null);
if (bevelled) {
this.getBevelledBBox(bbox, display);
} else {
const thickness = this.length2em(String(linethickness), .06);
w = -2 * this.pad;
if (thickness === 0) {
this.getAtopBBox(bbox, display);
} else {
this.getFractionBBox(bbox, display, thickness);
w -= .2;
}
w += bbox.w;
}
bbox.clean();
this.setChildPWidths(recompute, w);
}
/************************************************/
/**
* @param {BBox} bbox The buonding box to modify
* @param {boolean} display True for display-mode fractions
* @param {number} t The thickness of the line
*/
public getFractionBBox(bbox: BBox, display: boolean, t: number) {
const nbox = this.childNodes[0].getOuterBBox();
const dbox = this.childNodes[1].getOuterBBox();
const tex = this.font.params;
const a = tex.axis_height;
const {T, u, v} = this.getTUV(display, t);
bbox.combine(nbox, 0, a + T + Math.max(nbox.d * nbox.rscale, u));
bbox.combine(dbox, 0, a - T - Math.max(dbox.h * dbox.rscale, v));
bbox.w += 2 * this.pad + .2;
}
/**
* @param {boolean} display True for display-mode fractions
* @param {number} t The thickness of the line
* @return {Object} The expanded rule thickness (T), and baseline offsets
* for numerator and denomunator (u and v)
*/
public getTUV(display: boolean, t: number): {T: number, u: number, v: number} {
const tex = this.font.params;
const a = tex.axis_height;
const T = (display ? 3.5 : 1.5) * t;
return {T: (display ? 3.5 : 1.5) * t,
u: (display ? tex.num1 : tex.num2) - a - T,
v: (display ? tex.denom1 : tex.denom2) + a - T};
}
/************************************************/
/**
* @param {BBox} bbox The bounding box to modify
* @param {boolean} display True for display-mode fractions
*/
public getAtopBBox(bbox: BBox, display: boolean) {
const {u, v, nbox, dbox} = this.getUVQ(display);
bbox.combine(nbox, 0, u);
bbox.combine(dbox, 0, -v);
bbox.w += 2 * this.pad;
}
/**
* @param {boolean} display True for diplay-mode fractions
* @return {Object}
* The vertical offsets of the numerator (u), the denominator (v),
* the separation between the two, and the bboxes themselves.
*/
public getUVQ(display: boolean): {u: number, v: number, q: number, nbox: BBox, dbox: BBox} {
const nbox = this.childNodes[0].getOuterBBox();
const dbox = this.childNodes[1].getOuterBBox();
const tex = this.font.params;
//
// Initial offsets (u, v)
// Minimum separation (p)
// Actual separation with initial positions (q)
//
let [u, v] = (display ? [tex.num1, tex.denom1] : [tex.num3, tex.denom2]);
let p = (display ? 7 : 3) * tex.rule_thickness;
let q = (u - nbox.d * nbox.scale) - (dbox.h * dbox.scale - v);
//
// If actual separation is less than minimum, move them farther apart
//
if (q < p) {
u += (p - q) / 2;
v += (p - q) / 2;
q = p;
}
return {u, v, q, nbox, dbox};
}
/************************************************/
/**
* @param {BBox} bbox The boundng box to modify
* @param {boolean} display True for display-mode fractions
*/
public getBevelledBBox(bbox: BBox, display: boolean) {
const {u, v, delta, nbox, dbox} = this.getBevelData(display);
const lbox = this.bevel.getOuterBBox();
bbox.combine(nbox, 0, u);
bbox.combine(lbox, bbox.w - delta / 2, 0);
bbox.combine(dbox, bbox.w - delta / 2, v);
}
/**
* @param {boolean} display True for display-style fractions
* @return {Object} The height (H) of the bevel, horizontal offest (delta)
* vertical offsets (u and v) of the parts, and
* bounding boxes of the parts.
*/
public getBevelData(display: boolean): {
H: number, delta: number, u: number, v: number, nbox: BBox, dbox: BBox
} {
const nbox = this.childNodes[0].getOuterBBox();
const dbox = this.childNodes[1].getOuterBBox();
const delta = (display ? .4 : .15);
const H = Math.max(nbox.scale * (nbox.h + nbox.d), dbox.scale * (dbox.h + dbox.d)) + 2 * delta;
const a = this.font.params.axis_height;
const u = nbox.scale * (nbox.d - nbox.h) / 2 + a + delta;
const v = dbox.scale * (dbox.d - dbox.h) / 2 + a - delta;
return {H, delta, u, v, nbox, dbox};
}
/************************************************/
/**
* @override
*/
public canStretch(_direction: DIRECTION) {
return false;
}
/**
* @return {boolean} True if in display mode, false otherwise
*/
public isDisplay(): boolean {
const {displaystyle, scriptlevel} = this.node.attributes.getList('displaystyle', 'scriptlevel');
return displaystyle && scriptlevel === 0;
}
/**
* @override
*/
public getWrapWidth(i: number) {
const attributes = this.node.attributes;
if (attributes.get('bevelled')) {
return this.childNodes[i].getOuterBBox().w;
}
const w = this.getBBox().w;
const thickness = this.length2em(attributes.get('linethickness'));
return w - (thickness ? .2 : 0) - 2 * this.pad;
}
/**
* @override
*/
public getChildAlign(i: number) {
const attributes = this.node.attributes;
return (attributes.get('bevelled') ? 'left' : attributes.get(['numalign', 'denomalign'][i]) as string);
}
};
}
+137
View File
@@ -0,0 +1,137 @@
/*************************************************************
*
* Copyright (c) 2018-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview Implements the CommonMglyph wrapper mixin for the MmlMglyph object
*
* @author dpvc@mathjax.org (Davide Cervone)
*/
import {AnyWrapper, WrapperConstructor, Constructor} from '../Wrapper.js';
import {CommonTextNode} from './TextNode.js';
import {TextNode} from '../../../core/MmlTree/MmlNode.js';
import {BBox} from '../../../util/BBox.js';
/*****************************************************************/
/**
* The CommonMglyph interface
*/
export interface CommonMglyph extends AnyWrapper {
/**
* The image's width converted to em's
*/
width: number;
/**
* The image's height converted to em's
*/
height: number;
/*
* The image's valign values converted to em's
*/
valign: number;
/**
* TextNode used for deprecated fontfamily/index use case
*/
charWrapper: CommonTextNode;
/**
* Obtain the width, height, and valign.
* Note: Currently, the width and height must be specified explicitly, or they default to 1em
* Since loading the image may be asynchronous, it would require a restart.
* A future extension could implement this either by subclassing this object, or
* perhaps as a post-filter on the MathML input jax that adds the needed dimensions
*/
getParameters(): void;
}
/**
* Shorthand for the CommonMglyph constructor
*/
export type MglyphConstructor = Constructor<CommonMglyph>;
/*****************************************************************/
/**
* The CommonMglyph wrapper mixin for the MmlMglyph object
*
* @template T The Wrapper class constructor type
*/
export function CommonMglyphMixin<T extends WrapperConstructor>(Base: T): MglyphConstructor & T {
return class extends Base {
/**
* @override
*/
public width: number;
/**
* @override
*/
public height: number;
/**
* @override
*/
public valign: number;
/**
* @override
*/
public charWrapper: CommonTextNode;
/**
* @override
* @constructor
*/
constructor(...args: any[]) {
super(...args);
this.getParameters();
}
/**
* @override
*/
public getParameters() {
const {width, height, valign, src, index} =
this.node.attributes.getList('width', 'height', 'valign', 'src', 'index');
if (src) {
this.width = (width === 'auto' ? 1 : this.length2em(width));
this.height = (height === 'auto' ? 1 : this.length2em(height));
this.valign = this.length2em(valign || '0');
} else {
const text = String.fromCodePoint(parseInt(index as string));
const mmlFactory = this.node.factory;
this.charWrapper = this.wrap((mmlFactory.create('text') as TextNode).setText(text));
this.charWrapper.parent = this as any as AnyWrapper;
}
}
/**
* @override
*/
public computeBBox(bbox: BBox, _recompute: boolean = false) {
if (this.charWrapper) {
bbox.updateFrom(this.charWrapper.getBBox());
} else {
bbox.w = this.width;
bbox.h = this.height + this.valign;
bbox.d = -this.valign;
}
}
};
}
+58
View File
@@ -0,0 +1,58 @@
/*************************************************************
*
* Copyright (c) 2017-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview Implements the CommonMi wrapper mixin for the MmlMi object
*
* @author dpvc@mathjax.org (Davide Cervone)
*/
import {AnyWrapper, WrapperConstructor, Constructor} from '../Wrapper.js';
import {BBox} from '../../../util/BBox.js';
/*****************************************************************/
/**
* The CommonMi interface
*/
export interface CommonMi extends AnyWrapper {
}
/**
* Shorthand for the CommonMi constructor
*/
export type MiConstructor = Constructor<CommonMi>;
/*****************************************************************/
/**
* The CommonMi wrapper mixin for the MmlMi object
*
* @template T The Wrapper class constructor type
*/
export function CommonMiMixin<T extends WrapperConstructor>(Base: T): MiConstructor & T {
return class extends Base {
/**
* @override
*/
public computeBBox(bbox: BBox, _recompute: boolean = false) {
super.computeBBox(bbox);
this.copySkewIC(bbox);
}
};
}
+344
View File
@@ -0,0 +1,344 @@
/*************************************************************
*
* Copyright (c) 2018-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview Implements the CommonMmultiscripts wrapper mixin for the MmlMmultiscripts object
*
* @author dpvc@mathjax.org (Davide Cervone)
*/
import {AnyWrapper, Constructor} from '../Wrapper.js';
import {CommonMsubsup, MsubsupConstructor} from './msubsup.js';
import {BBox} from '../../../util/BBox.js';
/*****************************************************************/
/**
* The data about the scripts and base
*/
export type ScriptData = {
base: BBox;
sub: BBox; // combined bbox for all subscripts
sup: BBox; // combined bbox for all superscripts
psub: BBox; // combined bbox for all presubscripts
psup: BBox; // combined bbox for all presuperscripts
numPrescripts: number;
numScripts: number;
};
export type ScriptDataName = keyof ScriptData;
/**
* The lists of all the individual script bboxes
*/
export type ScriptLists = {
base: BBox[];
subList: BBox[];
supList: BBox[];
psubList: BBox[];
psupList: BBox[];
};
export type ScriptListName = keyof ScriptLists;
/**
* The type of script that follows the given type
*/
export const NextScript: {[key: string]: ScriptListName} = {
base: 'subList',
subList: 'supList',
supList: 'subList',
psubList: 'psupList',
psupList: 'psubList',
};
/**
* The names of the scripts (for looping)
*/
export const ScriptNames = ['sup', 'sup', 'psup', 'psub'] as ScriptDataName[];
/*****************************************************************/
/**
* The CommonMmultiscripts interface
*
* @template W The child-node Wrapper class
*/
export interface CommonMmultiscripts<W extends AnyWrapper> extends CommonMsubsup<W> {
/**
* The cached data for the various bounding boxes
*/
scriptData: ScriptData;
/**
* The index of the child following the <mprescripts/> tag
*/
firstPrescript: number;
/**
* @param {BBox} pre The prescript bounding box
* @param {BBox} post The postcript bounding box
* @return {BBox} The combined bounding box
*/
combinePrePost(pre: BBox, post: BBox): BBox;
/**
* Compute the bounding box information about all the scripts
*/
getScriptData(): void;
/**
* @return {ScriptLists} The bounding boxes for all the scripts divided into lists by position
*/
getScriptBBoxLists(): ScriptLists;
/**
* Pad the second list, if it is one short
*
* @param {BBox[]} list1 The first list
* @param {BBox[]} list2 The second list
*/
padLists(list1: BBox[], list2: BBox[]): void;
/**
* @param {BBox} bbox1 The bbox for the combined subscripts
* @param {BBox} bbox2 The bbox for the combined superscripts
* @param {BBox[]} list1 The list of subscripts to combine
* @param {BBox[]} list2 The list of superscripts to combine
*/
combineBBoxLists(bbox1: BBox, bbox2: BBox, list1: BBox[], list2: BBox[]): void;
/**
* @param {BBox} bbox The bounding box from which to get the (scaled) width, height, and depth
*/
getScaledWHD(bbox: BBox): void;
}
/**
* Shorthand for the CommonMmultiscripts constructor
*
* @template W The child-node Wrapper class
*/
export type MmultiscriptsConstructor<W extends AnyWrapper> = Constructor<CommonMmultiscripts<W>>;
/*****************************************************************/
/**
* The CommonMmultiscripts wrapper mixin for the MmlMmultiscripts object
*
* @template W The child-node Wrapper class
* @template T The Wrapper class constructor type
*/
export function CommonMmultiscriptsMixin<
W extends AnyWrapper,
T extends MsubsupConstructor<W>
>(Base: T): MmultiscriptsConstructor<W> & T {
return class extends Base {
/**
* The cached data for the various bounding boxes
*/
public scriptData: ScriptData = null;
/**
* The index of the child following the <mprescripts/> tag
*/
public firstPrescript = 0;
/**
* @override
*/
constructor(...args: any[]) {
super(...args);
this.getScriptData();
}
/*************************************************************/
/**
* @param {BBox} pre The prescript bounding box
* @param {BBox} post The postcript bounding box
* @return {BBox} The combined bounding box
*/
public combinePrePost(pre: BBox, post: BBox): BBox {
const bbox = new BBox(pre);
bbox.combine(post, 0, 0);
return bbox;
}
/*************************************************************/
/**
* @override
*/
public computeBBox(bbox: BBox, recompute: boolean = false) {
//
// Get the bounding boxes, and combine the pre- and post-scripts
// to get a common offset for both
//
const scriptspace = this.font.params.scriptspace;
const data = this.scriptData;
const sub = this.combinePrePost(data.sub, data.psub);
const sup = this.combinePrePost(data.sup, data.psup);
const [u, v] = this.getUVQ(sub, sup);
//
// Lay out the pre-scripts, then the base, then the post-scripts
//
bbox.empty();
if (data.numPrescripts) {
bbox.combine(data.psup, scriptspace, u);
bbox.combine(data.psub, scriptspace, v);
}
bbox.append(data.base);
if (data.numScripts) {
const w = bbox.w;
bbox.combine(data.sup, w, u);
bbox.combine(data.sub, w, v);
bbox.w += scriptspace;
}
bbox.clean();
this.setChildPWidths(recompute);
}
/**
* Compute the bounding box information about all the scripts
*/
public getScriptData() {
//
// Initialize the bounding box data
//
const data: ScriptData = this.scriptData = {
base: null, sub: BBox.empty(), sup: BBox.empty(), psub: BBox.empty(), psup: BBox.empty(),
numPrescripts: 0, numScripts: 0
};
//
// Get the bboxes for all the scripts and combine them into the scriptData
//
const lists = this.getScriptBBoxLists();
this.combineBBoxLists(data.sub, data.sup, lists.subList, lists.supList);
this.combineBBoxLists(data.psub, data.psup, lists.psubList, lists.psupList);
data.base = lists.base[0];
//
// Save the lengths and return the data
//
data.numPrescripts = lists.psubList.length;
data.numScripts = lists.subList.length;
}
/**
* @return {ScriptLists} The bounding boxes for all the scripts divided into lists by position
*/
public getScriptBBoxLists(): ScriptLists {
const lists: ScriptLists = {
base: [], subList: [], supList: [], psubList: [], psupList: []
};
//
// The first entry is the base, and then they altername sub- and superscripts.
// Once we find the <mprescripts/> element, switch to presub- and presuperscript lists.
//
let script: ScriptListName = 'base';
for (const child of this.childNodes) {
if (child.node.isKind('mprescripts')) {
script = 'psubList';
} else {
lists[script].push(child.getOuterBBox());
script = NextScript[script];
}
}
//
// The index of the first prescript (skip over base, sub- and superscripts, and mprescripts)
//
this.firstPrescript = lists.subList.length + lists.supList.length + 2;
//
// Make sure the lists are the same length
//
this.padLists(lists.subList, lists.supList);
this.padLists(lists.psubList, lists.psupList);
return lists;
}
/**
* Pad the second list, if it is one short
*
* @param {BBox[]} list1 The first list
* @param {BBox[]} list2 The second list
*/
public padLists(list1: BBox[], list2: BBox[]) {
if (list1.length > list2.length) {
list2.push(BBox.empty());
}
}
/**
* @param {BBox} bbox1 The bbox for the combined subscripts
* @param {BBox} bbox2 The bbox for the combined superscripts
* @param {BBox[]} list1 The list of subscripts to combine
* @param {BBox[]} list2 The list of superscripts to combine
*/
public combineBBoxLists(bbox1: BBox, bbox2: BBox, list1: BBox[], list2: BBox[]) {
for (let i = 0; i < list1.length; i++) {
const [w1, h1, d1] = this.getScaledWHD(list1[i]);
const [w2, h2, d2] = this.getScaledWHD(list2[i]);
const w = Math.max(w1, w2);
bbox1.w += w;
bbox2.w += w;
if (h1 > bbox1.h) bbox1.h = h1;
if (d1 > bbox1.d) bbox1.d = d1;
if (h2 > bbox2.h) bbox2.h = h2;
if (d2 > bbox2.d) bbox2.d = d2;
}
}
/**
* @param {BBox} bbox The bounding box from which to get the (scaled) width, height, and depth
*/
public getScaledWHD(bbox: BBox) {
const {w, h, d, rscale} = bbox;
return [w * rscale, h * rscale, d * rscale];
}
/*************************************************************/
/**
* @override
*/
public getUVQ(subbox: BBox, supbox: BBox) {
if (!this.UVQ) {
let [u, v, q] = [0, 0, 0];
if (subbox.h === 0 && subbox.d === 0) {
//
// Use placement for superscript only
//
u = this.getU();
} else if (supbox.h === 0 && supbox.d === 0) {
//
// Use placement for subsccript only
//
u = -this.getV();
} else {
//
// Use placement for both
//
[u, v, q] = super.getUVQ(subbox, supbox);
}
this.UVQ = [u, v, q];
}
return this.UVQ;
}
};
}
+70
View File
@@ -0,0 +1,70 @@
/*************************************************************
*
* Copyright (c) 2018-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview Implements the CommonMn wrapper mixin for the MmlMn object
*
* @author dpvc@mathjax.org (Davide Cervone)
*/
import {AnyWrapper, WrapperConstructor, Constructor} from '../Wrapper.js';
/*****************************************************************/
/**
* The CommonMn interface
*/
export interface CommonMn extends AnyWrapper {
}
/**
* Shorthand for the CommonMn constructor
*/
export type MnConstructor = Constructor<CommonMn>;
/*****************************************************************/
/**
* The CommonMn wrapper mixin for the MmlMn object
*
* @template T The Wrapper class constructor type
*/
export function CommonMnMixin<T extends WrapperConstructor>(Base: T): MnConstructor & T {
return class extends Base {
/**
* @override
*/
public remapChars(chars: number[]) {
//
// Convert a leading hyphen to a minus
//
if (chars.length) {
const text = this.font.getRemappedChar('mn', chars[0]);
if (text) {
const c = this.unicodeChars(text, this.variant);
if (c.length === 1) {
chars[0] = c[0];
} else {
chars = c.concat(chars.slice(1));
}
}
}
return chars;
}
};
}
+413
View File
@@ -0,0 +1,413 @@
/*************************************************************
*
* Copyright (c) 2017-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview Implements the CommonMo wrapper mixin for the MmlMo object
*
* @author dpvc@mathjax.org (Davide Cervone)
*/
import {AnyWrapper, WrapperConstructor, Constructor} from '../Wrapper.js';
import {MmlMo} from '../../../core/MmlTree/MmlNodes/mo.js';
import {BBox} from '../../../util/BBox.js';
import {unicodeChars} from '../../../util/string.js';
import {DelimiterData} from '../FontData.js';
import {DIRECTION, NOSTRETCH} from '../FontData.js';
/*****************************************************************/
/**
* Convert direction to letter
*/
export const DirectionVH: {[n: number]: string} = {
[DIRECTION.Vertical]: 'v',
[DIRECTION.Horizontal]: 'h'
};
/*****************************************************************/
/**
* The CommonMo interface
*/
export interface CommonMo extends AnyWrapper {
/**
* The font size that a stretched operator uses.
* If -1, then stretch arbitrarily, and bbox gives the actual height, depth, width
*/
size: number;
/**
* True if used as an accent in an munderover construct
*/
isAccent: boolean;
/**
* Get the (unmodified) bbox of the contents (before centering or setting accents to width 0)
*
* @param {BBox} bbox The bbox to fill
*/
protoBBox(bbox: BBox): void;
/**
* @return {number} Offset to the left by half the actual width of the accent
*/
getAccentOffset(): number;
/**
* @param {BBox} bbox The bbox to center, or null to compute the bbox
* @return {number} The offset to move the glyph to center it
*/
getCenterOffset(bbox?: BBox): number;
/**
* Determint variant for vertically/horizontally stretched character
*
* @param {number[]} WH size to stretch to, either [W] or [H, D]
* @param {boolean} exact True if not allowed to use delimiter factor and shortfall
*/
getStretchedVariant(WH: number[], exact?: boolean): void;
/**
* @param {string} name The name of the attribute to get
* @param {number} value The default value to use
* @return {number} The size in em's of the attribute (or the default value)
*/
getSize(name: string, value: number): number;
/**
* @param {number[]} WH Either [W] for width, [H, D] for height and depth, or [] for min/max size
* @return {number} Either the width or the total height of the character
*/
getWH(WH: number[]): number;
/**
* @param {number[]} WHD The [W] or [H, D] being requested from the parent mrow
* @param {number} D The full dimension (including symmetry, etc)
* @param {DelimiterData} C The delimiter data for the stretchy character
*/
getStretchBBox(WHD: number[], D: number, C: DelimiterData): void;
/**
* @param {number[]} WHD The [H, D] being requested from the parent mrow
* @param {number} HD The full height (including symmetry, etc)
* @param {DelimiterData} C The delimiter data for the stretchy character
* @return {number[]} The height and depth for the vertically stretched delimiter
*/
getBaseline(WHD: number[], HD: number, C: DelimiterData): number[];
/**
* Determine the size of the delimiter based on whether full extenders should be used or not.
*
* @param {number} D The requested size of the delimiter
* @param {DelimiterData} C The data for the delimiter
* @return {number} The final size of the assembly
*/
checkExtendedHeight(D: number, C: DelimiterData): number;
}
/**
* Shorthand for the CommonMo constructor
*/
export type MoConstructor = Constructor<CommonMo>;
/*****************************************************************/
/**
* The CommomMo wrapper mixin for the MmlMo object
*
* @template T The Wrapper class constructor type
*/
export function CommonMoMixin<T extends WrapperConstructor>(Base: T): MoConstructor & T {
return class extends Base {
/**
* The font size that a stretched operator uses.
* If -1, then stretch arbitrarily, and bbox gives the actual height, depth, width
*/
public size: number = null;
/**
* True if used as an accent in an munderover construct
*/
public isAccent: boolean;
/**
* @override
*/
constructor(...args: any[]) {
super(...args);
this.isAccent = (this.node as MmlMo).isAccent;
}
/**
* @override
*/
public computeBBox(bbox: BBox, _recompute: boolean = false) {
this.protoBBox(bbox);
if (this.node.attributes.get('symmetric') &&
this.stretch.dir !== DIRECTION.Horizontal) {
const d = this.getCenterOffset(bbox);
bbox.h += d;
bbox.d -= d;
}
if (this.node.getProperty('mathaccent') &&
(this.stretch.dir === DIRECTION.None || this.size >= 0)) {
bbox.w = 0;
}
}
/**
* Get the (unmodified) bbox of the contents (before centering or setting accents to width 0)
*
* @param {BBox} bbox The bbox to fill
*/
public protoBBox(bbox: BBox) {
const stretchy = (this.stretch.dir !== DIRECTION.None);
if (stretchy && this.size === null) {
this.getStretchedVariant([0]);
}
if (stretchy && this.size < 0) return;
super.computeBBox(bbox);
this.copySkewIC(bbox);
}
/**
* @return {number} Offset to the left by half the actual width of the accent
*/
public getAccentOffset(): number {
const bbox = BBox.empty();
this.protoBBox(bbox);
return -bbox.w / 2;
}
/**
* @param {BBox} bbox The bbox to center, or null to compute the bbox
* @return {number} The offset to move the glyph to center it
*/
public getCenterOffset(bbox: BBox = null): number {
if (!bbox) {
bbox = BBox.empty();
super.computeBBox(bbox);
}
return ((bbox.h + bbox.d) / 2 + this.font.params.axis_height) - bbox.h;
}
/**
* @override
*/
public getVariant() {
if (this.node.attributes.get('largeop')) {
this.variant = (this.node.attributes.get('displaystyle') ? '-largeop' : '-smallop');
return;
}
if (!this.node.attributes.getExplicit('mathvariant') &&
this.node.getProperty('pseudoscript') === false) {
this.variant = '-tex-variant';
return;
}
super.getVariant();
}
/**
* @override
*/
public canStretch(direction: DIRECTION) {
if (this.stretch.dir !== DIRECTION.None) {
return this.stretch.dir === direction;
}
const attributes = this.node.attributes;
if (!attributes.get('stretchy')) return false;
const c = this.getText();
if (Array.from(c).length !== 1) return false;
const delim = this.font.getDelimiter(c.codePointAt(0));
this.stretch = (delim && delim.dir === direction ? delim : NOSTRETCH);
return this.stretch.dir !== DIRECTION.None;
}
/**
* Determint variant for vertically/horizontally stretched character
*
* @param {number[]} WH size to stretch to, either [W] or [H, D]
* @param {boolean} exact True if not allowed to use delimiter factor and shortfall
*/
public getStretchedVariant(WH: number[], exact: boolean = false) {
if (this.stretch.dir !== DIRECTION.None) {
let D = this.getWH(WH);
const min = this.getSize('minsize', 0);
const max = this.getSize('maxsize', Infinity);
const mathaccent = this.node.getProperty('mathaccent');
//
// Clamp the dimension to the max and min
// then get the target size via TeX rules
//
D = Math.max(min, Math.min(max, D));
const df = this.font.params.delimiterfactor / 1000;
const ds = this.font.params.delimitershortfall;
const m = (min || exact ? D : mathaccent ? Math.min(D / df, D + ds) : Math.max(D * df, D - ds));
//
// Look through the delimiter sizes for one that matches
//
const delim = this.stretch;
const c = delim.c || this.getText().codePointAt(0);
let i = 0;
if (delim.sizes) {
for (const d of delim.sizes) {
if (d >= m) {
if (mathaccent && i) {
i--;
}
this.variant = this.font.getSizeVariant(c, i);
this.size = i;
if (delim.schar && delim.schar[i]) {
this.stretch = {...this.stretch, c: delim.schar[i]};
}
return;
}
i++;
}
}
//
// No size matches, so if we can make multi-character delimiters,
// record the data for that, otherwise, use the largest fixed size.
//
if (delim.stretch) {
this.size = -1;
this.invalidateBBox();
this.getStretchBBox(WH, this.checkExtendedHeight(D, delim), delim);
} else {
this.variant = this.font.getSizeVariant(c, i - 1);
this.size = i - 1;
}
}
}
/**
* @param {string} name The name of the attribute to get
* @param {number} value The default value to use
* @return {number} The size in em's of the attribute (or the default value)
*/
public getSize(name: string, value: number): number {
let attributes = this.node.attributes;
if (attributes.isSet(name)) {
value = this.length2em(attributes.get(name), 1, 1); // FIXME: should use height of actual character
}
return value;
}
/**
* @param {number[]} WH Either [W] for width, [H, D] for height and depth, or [] for min/max size
* @return {number} Either the width or the total height of the character
*/
public getWH(WH: number[]): number {
if (WH.length === 0) return 0;
if (WH.length === 1) return WH[0];
let [H, D] = WH;
const a = this.font.params.axis_height;
return (this.node.attributes.get('symmetric') ? 2 * Math.max(H - a, D + a) : H + D);
}
/**
* @param {number[]} WHD The [W] or [H, D] being requested from the parent mrow
* @param {number} D The full dimension (including symmetry, etc)
* @param {DelimiterData} C The delimiter data for the stretchy character
*/
public getStretchBBox(WHD: number[], D: number, C: DelimiterData) {
if (C.hasOwnProperty('min') && C.min > D) {
D = C.min;
}
let [h, d, w] = C.HDW;
if (this.stretch.dir === DIRECTION.Vertical) {
[h, d] = this.getBaseline(WHD, D, C);
} else {
w = D;
}
this.bbox.h = h;
this.bbox.d = d;
this.bbox.w = w;
}
/**
* @param {number[]} WHD The [H, D] being requested from the parent mrow
* @param {number} HD The full height (including symmetry, etc)
* @param {DelimiterData} C The delimiter data for the stretchy character
* @return {[number, number]} The height and depth for the vertically stretched delimiter
*/
public getBaseline(WHD: number[], HD: number, C: DelimiterData): [number, number] {
const hasWHD = (WHD.length === 2 && WHD[0] + WHD[1] === HD);
const symmetric = this.node.attributes.get('symmetric');
const [H, D] = (hasWHD ? WHD : [HD, 0]);
let [h, d] = [H + D, 0];
if (symmetric) {
//
// Center on the math axis
//
const a = this.font.params.axis_height;
if (hasWHD) {
h = 2 * Math.max(H - a, D + a);
}
d = h / 2 - a;
} else if (hasWHD) {
//
// Use the given depth (from mrow)
//
d = D;
} else {
//
// Use depth proportional to the normal-size character
// (when stretching for minsize or maxsize by itself)
//
let [ch, cd] = (C.HDW || [.75, .25]);
d = cd * (h / (ch + cd));
}
return [h - d, d];
}
/**
* @override
*/
public checkExtendedHeight(D: number, C: DelimiterData): number {
if (C.fullExt) {
const [extSize, endSize] = C.fullExt;
const n = Math.ceil(Math.max(0, D - endSize) / extSize);
D = endSize + n * extSize;
}
return D;
}
/**
* @override
*/
public remapChars(chars: number[]) {
const primes = this.node.getProperty('primes') as string;
if (primes) {
return unicodeChars(primes);
}
if (chars.length === 1) {
const parent = (this.node as MmlMo).coreParent().parent;
const isAccent = this.isAccent && !parent.isKind('mrow');
const map = (isAccent ? 'accent' : 'mo');
const text = this.font.getRemappedChar(map, chars[0]);
if (text) {
chars = this.unicodeChars(text, this.variant);
}
}
return chars;
}
};
}
+145
View File
@@ -0,0 +1,145 @@
/*************************************************************
*
* Copyright (c) 2017-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview Implements the CommonMpadded wrapper mixin for the MmlMpadded object
*
* @author dpvc@mathjax.org (Davide Cervone)
*/
import {AnyWrapper, WrapperConstructor, Constructor} from '../Wrapper.js';
import {BBox} from '../../../util/BBox.js';
import {Property} from '../../../core/Tree/Node.js';
/*****************************************************************/
/**
* The CommonMpadded interface
*/
export interface CommonMpadded extends AnyWrapper {
/**
* Get the content bounding box, and the change in size and offsets
* as specified by the parameters
*
* @return {number[]} The original height, depth, width, the changes in height, depth,
* and width, and the horizontal and vertical offsets of the content
*/
getDimens(): number[];
/**
* Get a particular dimension, which can be relative to any of the BBox dimensions,
* and can be an offset from the default size of the given dimension.
*
* @param {Property} length The value to be converted to a length in ems
* @param {BBox} bbox The bbox of the mpadded content
* @param {string=} d The default dimension to use for relative sizes ('w', 'h', or 'd')
* @param {number=} m The minimum value allowed for the dimension
* @return {number} The final dimension in ems
*/
dimen(length: Property, bbox: BBox, d?: string, m?: number): number;
}
/**
* Shorthand for the CommonMpadded constructor
*/
export type MpaddedConstructor = Constructor<CommonMpadded>;
/*****************************************************************/
/**
* The CommomMpadded wrapper for the MmlMpadded object
*
* @template T The Wrapper class constructor type
*/
export function CommonMpaddedMixin<T extends WrapperConstructor>(Base: T): MpaddedConstructor & T {
return class extends Base {
/**
* Get the content bounding box, and the change in size and offsets
* as specified by the parameters
*
* @return {number[]} The original height, depth, width, the changes in height, depth,
* and width, and the horizontal and vertical offsets of the content
*/
public getDimens(): number[] {
const values = this.node.attributes.getList('width', 'height', 'depth', 'lspace', 'voffset');
const bbox = this.childNodes[0].getBBox(); // get unmodified bbox of children
let {w, h, d} = bbox;
let W = w, H = h, D = d, x = 0, y = 0, dx = 0;
if (values.width !== '') w = this.dimen(values.width, bbox, 'w', 0);
if (values.height !== '') h = this.dimen(values.height, bbox, 'h', 0);
if (values.depth !== '') d = this.dimen(values.depth, bbox, 'd', 0);
if (values.voffset !== '') y = this.dimen(values.voffset, bbox);
if (values.lspace !== '') x = this.dimen(values.lspace, bbox);
const align = this.node.attributes.get('data-align') as string;
if (align) {
dx = this.getAlignX(w, bbox, align);
}
return [H, D, W, h - H, d - D, w - W, x, y, dx];
}
/**
* Get a particular dimension, which can be relative to any of the BBox dimensions,
* and can be an offset from the default size of the given dimension.
*
* @param {Property} length The value to be converted to a length in ems
* @param {BBox} bbox The bbox of the mpadded content
* @param {string} d The default dimension to use for relative sizes ('w', 'h', or 'd')
* @param {number} m The minimum value allowed for the dimension
* @return {number} The final dimension in ems
*/
public dimen(length: Property, bbox: BBox, d: string = '', m: number = null): number {
length = String(length);
const match = length.match(/width|height|depth/);
const size = (match ? bbox[match[0].charAt(0) as (keyof BBox)] :
(d ? bbox[d as (keyof BBox)] : 0)) as number;
let dimen = (this.length2em(length, size) || 0);
if (length.match(/^[-+]/) && d) {
dimen += size;
}
if (m != null) {
dimen = Math.max(m, dimen);
}
return dimen;
}
/**
* @override
*/
public computeBBox(bbox: BBox, recompute: boolean = false) {
const [H, D, W, dh, dd, dw] = this.getDimens();
bbox.w = W + dw;
bbox.h = H + dh;
bbox.d = D + dd;
this.setChildPWidths(recompute, bbox.w);
}
/**
* @override
*/
public getWrapWidth(_i: number) {
return this.getBBox().w;
}
/**
* @override
*/
public getChildAlign(_i: number) {
return this.node.attributes.get('data-align') as string || 'left';
}
};
}
+104
View File
@@ -0,0 +1,104 @@
/*************************************************************
*
* Copyright (c) 2017-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview Implements the CommonMroot wrapper mixin for the MmlMroot object
*
* @author dpvc@mathjax.org (Davide Cervone)
*/
import {Constructor} from '../../common/Wrapper.js';
import {CommonMsqrt, MsqrtConstructor} from './msqrt.js';
import {CommonMo} from './mo.js';
import {BBox} from '../../../util/BBox.js';
/*****************************************************************/
/**
* The CommonMroot interface
*/
export interface CommonMroot extends CommonMsqrt {
}
/**
* Shorthand for the CommonMroot constructor
*/
export type MrootConstructor = Constructor<CommonMroot>;
/*****************************************************************/
/**
* The CommonMroot wrapper mixin for the MmlMroot object (extends CommonMsqrt)
*
* @template T The Wrapper class constructor type
*/
export function CommonMrootMixin<T extends MsqrtConstructor>(Base: T): MrootConstructor & T {
return class extends Base {
/**
* @override
*/
get surd() {
return 2;
}
/**
* @override
*/
get root(): number {
return 1;
}
/**
* @override
*/
public combineRootBBox(BBOX: BBox, sbox: BBox, H: number) {
const bbox = this.childNodes[this.root].getOuterBBox();
const h = this.getRootDimens(sbox, H)[1];
BBOX.combine(bbox, 0, h);
}
/**
* @override
*/
public getRootDimens(sbox: BBox, H: number) {
const surd = this.childNodes[this.surd] as CommonMo;
const bbox = this.childNodes[this.root].getOuterBBox();
const offset = (surd.size < 0 ? .5 : .6) * sbox.w;
const {w, rscale} = bbox;
const W = Math.max(w, offset / rscale);
const dx = Math.max(0, W - w);
const h = this.rootHeight(bbox, sbox, surd.size, H);
const x = W * rscale - offset;
return [x, h, dx];
}
/**
* @param {BBox} rbox The bbox of the root
* @param {BBox} sbox The bbox of the surd
* @param {number} size The size of the surd
* @param {number} H The height of the root as a whole
* @return {number} The height of the root within the surd
*/
public rootHeight(rbox: BBox, sbox: BBox, size: number, H: number): number {
const h = sbox.h + sbox.d;
const b = (size < 0 ? 1.9 : .55 * h) - (h - H);
return b + Math.max(0, rbox.d * rbox.rscale);
}
};
}
+159
View File
@@ -0,0 +1,159 @@
/*************************************************************
*
* Copyright (c) 2017-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview Implements the CommonMrow wrapper minin for the MmlMrow object
*
* @author dpvc@mathjax.org (Davide Cervone)
*/
import {AnyWrapper, WrapperConstructor, Constructor} from '../Wrapper.js';
import {CommonMo} from './mo.js';
import {BBox} from '../../../util/BBox.js';
import {DIRECTION} from '../FontData.js';
/*****************************************************************/
/**
* The CommonMrow interface
*/
export interface CommonMrow extends AnyWrapper {
/**
* Handle vertical stretching of children to match height of
* other nodes in the row.
*/
stretchChildren(): void;
}
/**
* Shorthand for the CommonMrow constructor
*/
export type MrowConstructor = Constructor<CommonMrow>;
/*****************************************************************/
/**
* The CommonMrow wrapper mixin for the MmlMrow object
*
* @template T The Wrapper class constructor type
*/
export function CommonMrowMixin<T extends WrapperConstructor>(Base: T): MrowConstructor & T {
return class extends Base {
/**
* @override
*/
get fixesPWidth() {
return false;
}
/**
* @override
* @constructor
*/
constructor(...args: any[]) {
super(...args);
this.stretchChildren();
for (const child of this.childNodes) {
if (child.bbox.pwidth) {
this.bbox.pwidth = BBox.fullWidth;
break;
}
}
}
/**
* Handle vertical stretching of children to match height of
* other nodes in the row.
*/
public stretchChildren() {
let stretchy: AnyWrapper[] = [];
//
// Locate and count the stretchy children
//
for (const child of this.childNodes) {
if (child.canStretch(DIRECTION.Vertical)) {
stretchy.push(child);
}
}
let count = stretchy.length;
let nodeCount = this.childNodes.length;
if (count && nodeCount > 1) {
let H = 0, D = 0;
//
// If all the children are stretchy, find the largest one,
// otherwise, find the height and depth of the non-stretchy
// children.
//
let all = (count > 1 && count === nodeCount);
for (const child of this.childNodes) {
const noStretch = (child.stretch.dir === DIRECTION.None);
if (all || noStretch) {
let {h, d, rscale} = child.getOuterBBox(noStretch);
h *= rscale;
d *= rscale;
if (h > H) H = h;
if (d > D) D = d;
}
}
//
// Stretch the stretchable children
//
for (const child of stretchy) {
(child.coreMO() as CommonMo).getStretchedVariant([H, D]);
}
}
}
};
}
/*****************************************************************/
/*****************************************************************/
/**
* The CommonInferredMrow interface
*/
export interface CommonInferredMrow extends CommonMrow {
}
/**
* Shorthand for the CommonInferredMrow constructor
*/
export type InferredMrowConstructor = Constructor<CommonInferredMrow>;
/*****************************************************************/
/**
* The CommonInferredMrow wrapper mixin for the MmlInferredMrow object
*
* @template T The Wrapper class constructor type
*/
export function CommonInferredMrowMixin<T extends MrowConstructor>(Base: T): InferredMrowConstructor & T {
return class extends Base {
/**
* Since inferred rows don't produce a container span, we can't
* set a font-size for it, so we inherit the parent scale
*
* @override
*/
public getScale() {
this.bbox.scale = this.parent.bbox.scale;
this.bbox.rscale = 1;
}
};
}
+85
View File
@@ -0,0 +1,85 @@
/*************************************************************
*
* Copyright (c) 2017-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview Implements the CommonMs wrapper mixin for the MmlMs object
*
* @author dpvc@mathjax.org (Davide Cervone)
*/
import {AnyWrapper, WrapperConstructor, Constructor} from '../Wrapper.js';
/*****************************************************************/
/**
* The CommonMs interface
*/
export interface CommonMs extends AnyWrapper {
/**
* Create a text wrapper with the given text;
*
* @param {string} text The text for the wrapped element
* @return {CommonWrapper} The wrapped text node
*/
createText(text: string): AnyWrapper;
}
/**
* Shorthand for the CommonMs constructor
*/
export type MsConstructor = Constructor<CommonMs>;
/*****************************************************************/
/**
* The CommonMs wrapper mixin for the MmlMs object
*
* @template T The Wrapper class constructor type
*/
export function CommonMsMixin<T extends WrapperConstructor>(Base: T): MsConstructor & T {
return class extends Base {
/**
* Add the quote characters to the wrapper children so they will be output
*
* @override
*/
constructor(...args: any[]) {
super(...args);
const attributes = this.node.attributes;
let quotes = attributes.getList('lquote', 'rquote');
if (this.variant !== 'monospace') {
if (!attributes.isSet('lquote') && quotes.lquote === '"') quotes.lquote = '\u201C';
if (!attributes.isSet('rquote') && quotes.rquote === '"') quotes.rquote = '\u201D';
}
this.childNodes.unshift(this.createText(quotes.lquote as string));
this.childNodes.push(this.createText(quotes.rquote as string));
}
/**
* Create a text wrapper with the given text;
*
* @param {string} text The text for the wrapped element
* @return {AnyWrapper} The wrapped text node
*/
public createText(text: string): AnyWrapper {
const node = this.wrap(this.mmlText(text));
node.parent = this;
return node;
}
};
}
+69
View File
@@ -0,0 +1,69 @@
/*************************************************************
*
* Copyright (c) 2017-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview Implements the CommonMspace wrapper mixin for the MmlMspace object
*
* @author dpvc@mathjax.org (Davide Cervone)
*/
import {AnyWrapper, WrapperConstructor, Constructor} from '../Wrapper.js';
import {BBox} from '../../../util/BBox.js';
/*****************************************************************/
/**
* The CommonMspance interface
*/
export interface CommonMspace extends AnyWrapper {
}
/**
* Shorthand for the CommonMspace constructor
*/
export type MspaceConstructor = Constructor<CommonMspace>;
/*****************************************************************/
/**
* The CommonMspace wrapper mixin for the MmlMspace object
*
* @template T The Wrapper class constructor type
*/
export function CommonMspaceMixin<T extends WrapperConstructor>(Base: T): MspaceConstructor & T {
return class extends Base {
/**
* @override
*/
public computeBBox(bbox: BBox, _recompute: boolean = false) {
const attributes = this.node.attributes;
bbox.w = this.length2em(attributes.get('width'), 0);
bbox.h = this.length2em(attributes.get('height'), 0);
bbox.d = this.length2em(attributes.get('depth'), 0);
}
/**
* No contents, so no need for variant class
*
* @override
*/
public handleVariant() {
}
};
}
+197
View File
@@ -0,0 +1,197 @@
/*************************************************************
*
* Copyright (c) 2017-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview Implements the CommonMsqrt wrapper for the MmlMsqrt object
*
* @author dpvc@mathjax.org (Davide Cervone)
*/
import {AnyWrapper, WrapperConstructor, Constructor} from '../Wrapper.js';
import {CommonMo} from './mo.js';
import {BBox} from '../../../util/BBox.js';
import {DIRECTION} from '../FontData.js';
/*****************************************************************/
/**
* The CommonMsqrt interface
*/
export interface CommonMsqrt extends AnyWrapper {
/**
* The index of the base of the root in childNodes
*/
readonly base: number;
/**
* The index of the surd in childNodes
*/
readonly surd: number;
/**
* The index of the root in childNodes (or null if none)
*/
readonly root: number;
/**
* The requested height of the stretched surd character
*/
surdH: number;
/**
* Combine the bounding box of the root (overridden in mroot)
*
* @param {BBox} bbox The bounding box so far
* @param {BBox} sbox The bounding box of the surd
* @param {number} H The height of the root as a whole
*/
combineRootBBox(bbox: BBox, sbox: BBox, H: number): void;
/**
* @param {BBox} sbox The bounding box for the surd character
* @return {number[]} The p, q, and x values for the TeX layout computations
*/
getPQ(sbox: BBox): number[];
/**
* @param {BBox} sbox The bounding box of the surd
* @param {number} H The height of the root as a whole
* @return {number[]} The x offset of the surd, and the height, x offset, and scale of the root
*/
getRootDimens(sbox: BBox, H: Number): number[];
}
/**
* Shorthand for the CommonMsqrt constructor
*/
export type MsqrtConstructor = Constructor<CommonMsqrt>;
/*****************************************************************/
/**
* The CommonMsqrt wrapper mixin for the MmlMsqrt object
*
* @template T The Wrapper class constructor type
*/
export function CommonMsqrtMixin<T extends WrapperConstructor>(Base: T): MsqrtConstructor & T {
return class extends Base {
/**
* @return {number} The index of the base of the root in childNodes
*/
get base(): number {
return 0;
}
/**
* @return {number} The index of the surd in childNodes
*/
get surd(): number {
return 1;
}
/**
* @return {number} The index of the root in childNodes (or null if none)
*/
get root(): number {
return null;
}
/**
* The requested height of the stretched surd character
*/
public surdH: number;
/**
* Add the surd character so we can display it later
*
* @override
*/
constructor(...args: any[]) {
super(...args);
const surd = this.createMo('\u221A');
surd.canStretch(DIRECTION.Vertical);
const {h, d} = this.childNodes[this.base].getOuterBBox();
const t = this.font.params.rule_thickness;
const p = (this.node.attributes.get('displaystyle') ? this.font.params.x_height : t);
this.surdH = h + d + 2 * t + p / 4;
(surd as CommonMo).getStretchedVariant([this.surdH - d, d], true);
}
/**
* @override
*/
public createMo(text: string) {
const node = super.createMo(text);
this.childNodes.push(node);
return node;
}
/**
* @override
*/
public computeBBox(bbox: BBox, recompute: boolean = false) {
const surdbox = this.childNodes[this.surd].getBBox();
const basebox = new BBox(this.childNodes[this.base].getOuterBBox());
const q = this.getPQ(surdbox)[1];
const t = this.font.params.rule_thickness;
const H = basebox.h + q + t;
const [x] = this.getRootDimens(surdbox, H);
bbox.h = H + t;
this.combineRootBBox(bbox, surdbox, H);
bbox.combine(surdbox, x, H - surdbox.h);
bbox.combine(basebox, x + surdbox.w, 0);
bbox.clean();
this.setChildPWidths(recompute);
}
/**
* Combine the bounding box of the root (overridden in mroot)
*
* @param {BBox} bbox The bounding box so far
* @param {BBox} sbox The bounding box of the surd
* @param {number} H The height of the root as a whole
*/
public combineRootBBox(_bbox: BBox, _sbox: BBox, _H: number) {
}
/**
* @param {BBox} sbox The bounding box for the surd character
* @return {[number, number]} The p, q, and x values for the TeX layout computations
*/
public getPQ(sbox: BBox): [number, number] {
const t = this.font.params.rule_thickness;
const p = (this.node.attributes.get('displaystyle') ? this.font.params.x_height : t);
const q = (sbox.h + sbox.d > this.surdH ?
((sbox.h + sbox.d) - (this.surdH - 2 * t - p / 2)) / 2 :
t + p / 4);
return [p, q];
}
/**
* @param {BBox} sbox The bounding box of the surd
* @param {number} H The height of the root as a whole
* @return {[number, number, number, number]} The x offset of the surd, and
* the height, x offset, and scale of the root
*/
public getRootDimens(_sbox: BBox, _H: number): [number, number, number, number] {
return [0, 0, 0, 0];
}
};
}
+286
View File
@@ -0,0 +1,286 @@
/*************************************************************
*
* Copyright (c) 2017-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview Implements the CommonMsubsup wrapper mixin for the MmlMsubsup object
* and the special cases CommonMsub and CommonMsup
*
* @author dpvc@mathjax.org (Davide Cervone)
*/
import {AnyWrapper, Constructor} from '../Wrapper.js';
import {CommonScriptbase, ScriptbaseConstructor} from './scriptbase.js';
import {BBox} from '../../../util/BBox.js';
import {MmlMsubsup, MmlMsub, MmlMsup} from '../../../core/MmlTree/MmlNodes/msubsup.js';
/*****************************************************************/
/**
* The CommonMsub interface
*
* @template W The child-node Wrapper class
*/
export interface CommonMsub<W extends AnyWrapper> extends CommonScriptbase<W> {
}
/**
* Shorthand for the CommonMsub constructor
*
* @template W The child-node Wrapper class
*/
export type MsubConstructor<W extends AnyWrapper> = Constructor<CommonMsub<W>>;
/*****************************************************************/
/**
* The CommonMsub wrapper mixin for the MmlMsub object
*
* @template W The child-node Wrapper class
* @template T The Wrapper class constructor type
*/
export function CommonMsubMixin<
W extends AnyWrapper,
T extends ScriptbaseConstructor<W>
>(Base: T): MsubConstructor<W> & T {
return class extends Base {
/**
* Do not include italic correction
*/
public static useIC: boolean = false;
/**
* @override
*/
public get scriptChild() {
return this.childNodes[(this.node as MmlMsub).sub];
}
/**
* Get the shift for the subscript
*
* @override
*/
public getOffset() {
return [0, -this.getV()];
}
};
}
/*****************************************************************/
/**
* The CommonMsup interface
*
* @template W The child-node Wrapper class
*/
export interface CommonMsup<W extends AnyWrapper> extends CommonScriptbase<W> {
}
/**
* Shorthand for the CommonMsup constructor
*
* @template W The child-node Wrapper class
*/
export type MsupConstructor<W extends AnyWrapper> = Constructor<CommonMsup<W>>;
/*****************************************************************/
/**
* The CommonMsup wrapper mixin for the MmlMsup object
*
* @template W The child-node Wrapper class
* @template T The Wrapper class constructor type
*/
export function CommonMsupMixin<
W extends AnyWrapper,
T extends ScriptbaseConstructor<W>
>(Base: T): MsupConstructor<W> & T {
return class extends Base {
/**
* @override
*/
public get scriptChild() {
return this.childNodes[(this.node as MmlMsup).sup];
}
/**
* Get the shift for the superscript
*
* @override
*/
public getOffset() {
const x = this.getAdjustedIc() - (this.baseRemoveIc ? 0 : this.baseIc);
return [x, this.getU()];
}
};
}
/*****************************************************************/
/**
* The CommonMsubsup interface
*
* @template W The child-node Wrapper class
*/
export interface CommonMsubsup<W extends AnyWrapper> extends CommonScriptbase<W> {
/**
* Cached values for the script offsets and separation (so if they are
* computed in computeBBox(), they don't have to be recomputed during output)
*/
UVQ: number[];
/**
* The wrapper for the subscript
*/
readonly subChild: W;
/**
* The wrapper for the superscript
*/
readonly supChild: W;
/**
* Get the shift for the scripts and their separation (TeXBook Appendix G 18adef)
*
* @param {BBox} subbox The bounding box of the superscript
* @param {BBox} supbox The bounding box of the subscript
* @return {number[]} The vertical offsets for super and subscripts, and the space between them
*/
getUVQ(subbox?: BBox, supbox?: BBox): number[];
}
/**
* Shorthand for the CommonMsubsup constructor
*
* @template W The child-node Wrapper class
*/
export type MsubsupConstructor<W extends AnyWrapper> = Constructor<CommonMsubsup<W>>;
/*****************************************************************/
/**
* The CommomMsubsup wrapper for the MmlMsubsup object
*
* @template W The child-node Wrapper class
* @template T The Wrapper class constructor type
*/
export function CommonMsubsupMixin<
W extends AnyWrapper,
T extends ScriptbaseConstructor<W>
>(Base: T): MsubsupConstructor<W> & T {
return class extends Base {
/**
* Do not include italic correction
*/
public static useIC: boolean = false;
/**
* Cached values for the script offsets and separation (so if they are
* computed in computeBBox(), they don't have to be recomputed during output)
*/
public UVQ: number[] = null;
/**
* @return {W} The wrapper for the subscript
*/
public get subChild(): W {
return this.childNodes[(this.node as MmlMsubsup).sub];
}
/**
* @return {W} The wrapper for the superscript
*/
public get supChild(): W {
return this.childNodes[(this.node as MmlMsubsup).sup];
}
/**
* @override
*/
public computeBBox(bbox: BBox, recompute: boolean = false) {
const basebox = this.baseChild.getOuterBBox();
const [subbox, supbox] = [this.subChild.getOuterBBox(), this.supChild.getOuterBBox()];
bbox.empty();
bbox.append(basebox);
const w = this.getBaseWidth();
const x = this.getAdjustedIc();
const [u, v] = this.getUVQ();
bbox.combine(subbox, w, v);
bbox.combine(supbox, w + x, u);
bbox.w += this.font.params.scriptspace;
bbox.clean();
this.setChildPWidths(recompute);
}
/**
* Get the shift for the scripts and their separation (TeXBook Appendix G 18adef)
*
* @param {BBox} subbox The bounding box of the superscript
* @param {BBox} supbox The bounding box of the subscript
* @return {number[]} The vertical offsets for super and subscripts, and the space between them
*/
public getUVQ(
subbox: BBox = this.subChild.getOuterBBox(),
supbox: BBox = this.supChild.getOuterBBox()
): number[] {
const basebox = this.baseCore.getOuterBBox();
if (this.UVQ) return this.UVQ;
const tex = this.font.params;
const t = 3 * tex.rule_thickness;
const subscriptshift = this.length2em(this.node.attributes.get('subscriptshift'), tex.sub2);
const drop = this.baseCharZero(basebox.d * this.baseScale + tex.sub_drop * subbox.rscale);
//
// u and v are the veritcal shifts of the scripts, initially set to minimum values and then adjusted
//
let [u, v] = [this.getU(), Math.max(drop, subscriptshift)];
//
// q is the space currently between the super- and subscripts.
// If it is less than 3 rule thicknesses,
// increase the subscript offset to make the space 3 rule thicknesses
// If the bottom of the superscript is below 4/5 of the x-height
// raise both the super- and subscripts by the difference
// (make the bottom of the superscript be at 4/5 the x-height, and the
// subscript 3 rule thickness below that).
//
let q = (u - supbox.d * supbox.rscale) - (subbox.h * subbox.rscale - v);
if (q < t) {
v += t - q;
const p = (4 / 5) * tex.x_height - (u - supbox.d * supbox.rscale);
if (p > 0) {
u += p;
v -= p;
}
}
//
// Make sure the shifts are at least the minimum amounts and
// return the shifts and the space between the scripts
//
u = Math.max(this.length2em(this.node.attributes.get('superscriptshift'), u), u);
v = Math.max(this.length2em(this.node.attributes.get('subscriptshift'), v), v);
q = (u - supbox.d * supbox.rscale) - (subbox.h * subbox.rscale - v);
this.UVQ = [u, -v, q];
return this.UVQ;
}
};
}
File diff suppressed because it is too large Load Diff
+83
View File
@@ -0,0 +1,83 @@
/*************************************************************
*
* Copyright (c) 2018-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview Implements the CommonMtd wrapper mixin for the MmlMtd object
*
* @author dpvc@mathjax.org (Davide Cervone)
*/
import {AnyWrapper, WrapperConstructor, Constructor} from '../Wrapper.js';
import {CommonMtable} from '../../common/Wrappers/mtable.js';
import {CommonMtr} from '../../common/Wrappers/mtr.js';
/*****************************************************************/
/**
* The CommonMtd interface
*/
export interface CommonMtd extends AnyWrapper {
}
/**
* Shorthand for the CommonMtd constructor
*/
export type MtdConstructor = Constructor<CommonMtd>;
/*****************************************************************/
/**
* The CommonMtd wrapper mixin for the MmlMtd object
*
* @template T The Wrapper class constructor type
*/
export function CommonMtdMixin<T extends WrapperConstructor>(Base: T): MtdConstructor & T {
return class extends Base {
/**
* @override
*/
get fixesPWidth() {
return false;
}
/**
* @override
*/
public invalidateBBox() {
this.bboxComputed = false;
}
/**
* @override
*/
public getWrapWidth(_j: number) {
const table = this.parent.parent as any as CommonMtable<AnyWrapper, CommonMtr<AnyWrapper>>;
const row = this.parent as CommonMtr<AnyWrapper>;
const i = this.node.childPosition() - (row.labeled ? 1 : 0);
return (typeof(table.cWidths[i]) === 'number' ? table.cWidths[i] : table.getTableData().W[i]) as number;
}
/**
* @override
*/
public getChildAlign(_i: number) {
return this.node.attributes.get('columnalign') as string;
}
};
}
+86
View File
@@ -0,0 +1,86 @@
/*************************************************************
*
* Copyright (c) 2019-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview Implements the CommonMtext wrapper mixin for the MmlMtext object
*
* @author dpvc@mathjax.org (Davide Cervone)
*/
import {AnyWrapper, WrapperConstructor, Constructor} from '../Wrapper.js';
/*****************************************************************/
/**
* The CommonMtext interface
*/
export interface CommonMtext extends AnyWrapper {
}
/**
* Shorthand for the CommonMtext constructor
*/
export type MtextConstructor = Constructor<CommonMtext>;
/*****************************************************************/
/**
* The CommonMtext wrapper mixin for the MmlMtext object
*
* @template T The Wrapper class constructor type
*/
export function CommonMtextMixin<T extends WrapperConstructor>(Base: T): MtextConstructor & T {
return class extends Base {
/**
* The font-family, weight, and style to use for the variants when mtextInheritFont
* is true or mtextFont is specified. If not in this list, then the font's
* getCssFont() is called. When the font family is not specified (as in these four),
* the inherited or specified font is used.
*/
public static INHERITFONTS = {
normal: ['', false, false],
bold: ['', false, true],
italic: ['', true, false],
'bold-italic': ['', true, true]
};
/**
* @override
*/
protected getVariant() {
const options = this.jax.options;
const data = this.jax.math.outputData;
//
// If the font is to be inherited from the surrounding text, check the mathvariant
// and see if it allows for inheritance. If so, set the variant appropriately,
// otherwise get the usual variant.
//
const merror = ((!!data.merrorFamily || !!options.merrorFont) && this.node.Parent.isKind('merror'));
if (!!data.mtextFamily || !!options.mtextFont || merror) {
const variant = this.node.attributes.get('mathvariant') as string;
const font = (this.constructor as any).INHERITFONTS[variant] || this.jax.font.getCssFont(variant);
const family = font[0] || (merror ? data.merrorFamily || options.merrorFont :
data.mtextFamily || options.mtextFont);
this.variant = this.explicitVariant(family, font[2] ? 'bold' : '', font[1] ? 'italic' : '');
return;
}
super.getVariant();
}
};
}
+277
View File
@@ -0,0 +1,277 @@
/*************************************************************
*
* Copyright (c) 2017-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview Implements the CcommonMtr wrapper mixin for the MmlMtr object
* and CommonMlabeledtr wrapper mixin for MmlMlabeledtr
*
* @author dpvc@mathjax.org (Davide Cervone)
*/
import {AnyWrapper, WrapperConstructor, Constructor} from '../Wrapper.js';
import {CommonMo} from './mo.js';
import {BBox} from '../../../util/BBox.js';
import {DIRECTION} from '../FontData.js';
/*****************************************************************/
/**
* The CommonMtr interface
*
* @template C The class for table cells
*/
export interface CommonMtr<C extends AnyWrapper> extends AnyWrapper {
/**
* The number of mtd's in the mtr
*/
readonly numCells: number;
/**
* True if this is a labeled row
*/
readonly labeled: boolean;
/**
* The child nodes that are part of the table (no label node)
*/
readonly tableCells: C[];
/**
* @override;
*/
childNodes: C[];
/**
* @param {number} i The index of the child to get (skipping labels)
* @return {C} The ith child node wrapper
*/
getChild(i: number): C;
/**
* @return {BBox[]} An array of the bounding boxes for the mtd's in the row
*/
getChildBBoxes(): BBox[];
/**
* Handle vertical stretching of cells to match height of
* other cells in the row.
*
* @param {number[]=} HD The total height and depth for the row [H, D]
*
* If this isn't specified, the maximum height and depth is computed.
*/
stretchChildren(HD?: number[]): void;
}
/**
* Shorthand for the CommonMtr constructor
*
* @template C The class for table cells
*/
export type MtrConstructor<C extends AnyWrapper> = Constructor<CommonMtr<C>>;
/*****************************************************************/
/**
* The CommonMtr wrapper for the MmlMtr object
*
* @template C The class for table cells
* @template T The Wrapper class constructor type
*/
export function CommonMtrMixin<
C extends AnyWrapper,
T extends WrapperConstructor
>(Base: T): MtrConstructor<C> & T {
return class extends Base {
/**
* @override
*/
get fixesPWidth() {
return false;
}
/**
* @return {number} The number of mtd's in the mtr
*/
get numCells(): number {
return this.childNodes.length;
}
/**
* @return {boolean} True if this is a labeled row
*/
get labeled(): boolean {
return false;
}
/**
* @return {C[]} The child nodes that are part of the table (no label node)
*/
get tableCells(): C[] {
return this.childNodes;
}
/**
* @param {number} i The index of the child to get (skipping labels)
* @return {C} The ith child node wrapper
*/
public getChild(i: number): C {
return this.childNodes[i];
}
/**
* @return {BBox[]} An array of the bounding boxes for the mtd's in the row
*/
public getChildBBoxes(): BBox[] {
return this.childNodes.map(cell => cell.getBBox());
}
/**
* Handle vertical stretching of cells to match height of
* other cells in the row.
*
* @param {number[]} HD The total height and depth for the row [H, D]
*
* If this isn't specified, the maximum height and depth is computed.
*/
public stretchChildren(HD: number[] = null) {
let stretchy: AnyWrapper[] = [];
let children = (this.labeled ? this.childNodes.slice(1) : this.childNodes);
//
// Locate and count the stretchy children
//
for (const mtd of children) {
const child = mtd.childNodes[0];
if (child.canStretch(DIRECTION.Vertical)) {
stretchy.push(child);
}
}
let count = stretchy.length;
let nodeCount = this.childNodes.length;
if (count && nodeCount > 1) {
if (HD === null) {
let H = 0, D = 0;
//
// If all the children are stretchy, find the largest one,
// otherwise, find the height and depth of the non-stretchy
// children.
//
let all = (count > 1 && count === nodeCount);
for (const mtd of children) {
const child = mtd.childNodes[0];
const noStretch = (child.stretch.dir === DIRECTION.None);
if (all || noStretch) {
const {h, d} = child.getBBox(noStretch);
if (h > H) {
H = h;
}
if (d > D) {
D = d;
}
}
}
HD = [H, D];
}
//
// Stretch the stretchable children
//
for (const child of stretchy) {
(child.coreMO() as CommonMo).getStretchedVariant(HD);
}
}
}
};
}
/*****************************************************************/
/**
* The CommonMlabeledtr interface
*
* @template C The class for table cells
*/
export interface CommonMlabeledtr<C extends AnyWrapper> extends CommonMtr<C> {
}
/**
* Shorthand for the CommonMlabeledtr constructor
*
* @template C The class for table cells
*/
export type MlabeledtrConstructor<C extends AnyWrapper> = Constructor<CommonMlabeledtr<C>>;
/*****************************************************************/
/**
* The CommonMlabeledtr wrapper mixin for the MmlMlabeledtr object
*
* @template C The class for table cells
* @template T The Wrapper class constructor type
*/
export function CommonMlabeledtrMixin<
C extends AnyWrapper,
T extends MtrConstructor<C>
>(Base: T): MlabeledtrConstructor<C> & T {
return class extends Base {
/**
* @override
*/
get numCells() {
//
// Don't include the label mtd
//
return Math.max(0, this.childNodes.length - 1);
}
/**
* @override
*/
get labeled() {
return true;
}
/**
* @override
*/
get tableCells() {
return this.childNodes.slice(1) as C[];
}
/**
* @override
*/
public getChild(i: number) {
return this.childNodes[i + 1] as C;
}
/**
* @override
*/
public getChildBBoxes() {
//
// Don't include the label mtd
//
return this.childNodes.slice(1).map(cell => cell.getBBox());
}
};
}
+287
View File
@@ -0,0 +1,287 @@
/*************************************************************
*
* Copyright (c) 2017-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview Implements the CommonMunderover wrapper mixin for the MmlMunderover object
* and the special cases CommonMunder and CommonMsup
*
* @author dpvc@mathjax.org (Davide Cervone)
*/
import {AnyWrapper, Constructor} from '../Wrapper.js';
import {CommonScriptbase, ScriptbaseConstructor} from './scriptbase.js';
import {MmlMunderover, MmlMunder, MmlMover} from '../../../core/MmlTree/MmlNodes/munderover.js';
import {BBox} from '../../../util/BBox.js';
/*****************************************************************/
/**
* The CommonMunder interface
*
* @template W The child-node Wrapper class
*/
export interface CommonMunder<W extends AnyWrapper> extends CommonScriptbase<W> {
}
/**
* Shorthand for the CommonMunder constructor
*
* @template W The child-node Wrapper class
*/
export type MunderConstructor<W extends AnyWrapper> = Constructor<CommonMunder<W>>;
/*****************************************************************/
/**
* The CommonMunder wrapper mixin for the MmlMunder object
*
* @template W The child-node Wrapper class
* @template T The Wrapper class constructor type
*/
export function CommonMunderMixin<
W extends AnyWrapper,
T extends ScriptbaseConstructor<W>
>(Base: T): MunderConstructor<W> & T {
return class extends Base {
/**
* @override
*/
public get scriptChild() {
return this.childNodes[(this.node as MmlMunder).under];
}
/**
* @override
* @constructor
*/
constructor(...args: any[]) {
super(...args);
this.stretchChildren();
}
/**
* @override
*/
public computeBBox(bbox: BBox, recompute: boolean = false) {
if (this.hasMovableLimits()) {
super.computeBBox(bbox, recompute);
return;
}
bbox.empty();
const basebox = this.baseChild.getOuterBBox();
const underbox = this.scriptChild.getOuterBBox();
const v = this.getUnderKV(basebox, underbox)[1];
const delta = (this.isLineBelow ? 0 : this.getDelta(true));
const [bw, uw] = this.getDeltaW([basebox, underbox], [0, -delta]);
bbox.combine(basebox, bw, 0);
bbox.combine(underbox, uw, v);
bbox.d += this.font.params.big_op_spacing5;
bbox.clean();
this.setChildPWidths(recompute);
}
};
}
/*****************************************************************/
/**
* The CommonMover interface
*
* @template W The child-node Wrapper class
*/
export interface CommonMover<W extends AnyWrapper> extends CommonScriptbase<W> {
}
/**
* Shorthand for the CommonMover constructor
*
* @template W The child-node Wrapper class
*/
export type MoverConstructor<W extends AnyWrapper> = Constructor<CommonMover<W>>;
/*****************************************************************/
/**
* The CommonMover wrapper mixin for the MmlMover object
*
* @template W The child-node Wrapper class
* @template T The Wrapper class constructor type
*/
export function CommonMoverMixin<
W extends AnyWrapper,
T extends ScriptbaseConstructor<W>
>(Base: T): MoverConstructor<W> & T {
return class extends Base {
/**
* @override
*/
public get scriptChild() {
return this.childNodes[(this.node as MmlMover).over];
}
/**
* @override
* @constructor
*/
constructor(...args: any[]) {
super(...args);
this.stretchChildren();
}
/**
* @override
*/
public computeBBox(bbox: BBox) {
if (this.hasMovableLimits()) {
super.computeBBox(bbox);
return;
}
bbox.empty();
const basebox = this.baseChild.getOuterBBox();
const overbox = this.scriptChild.getOuterBBox();
if (this.node.attributes.get('accent')) {
basebox.h = Math.max(basebox.h, this.font.params.x_height * basebox.scale);
}
const u = this.getOverKU(basebox, overbox)[1];
const delta = (this.isLineAbove ? 0 : this.getDelta());
const [bw, ow] = this.getDeltaW([basebox, overbox], [0, delta]);
bbox.combine(basebox, bw, 0);
bbox.combine(overbox, ow, u);
bbox.h += this.font.params.big_op_spacing5;
bbox.clean();
}
};
}
/*****************************************************************/
/**
* The CommonMunderover interface
*
* @template W The child-node Wrapper class
*/
export interface CommonMunderover<W extends AnyWrapper> extends CommonScriptbase<W> {
/*
* The wrapped under node
*/
readonly underChild: W;
/*
* The wrapped overder node
*/
readonly overChild: W;
}
/**
* Shorthand for the CommonMunderover constructor
*
* @template W The child-node Wrapper class
*/
export type MunderoverConstructor<W extends AnyWrapper> = Constructor<CommonMunderover<W>>;
/*****************************************************************/
/*
* The CommonMunderover wrapper for the MmlMunderover object
*
* @template W The child-node Wrapper class
* @template T The Wrapper class constructor type
*/
export function CommonMunderoverMixin<
W extends AnyWrapper,
T extends ScriptbaseConstructor<W>
>(Base: T): MunderoverConstructor<W> & T {
return class extends Base {
/*
* @return {W} The wrapped under node
*/
public get underChild() {
return this.childNodes[(this.node as MmlMunderover).under];
}
/*
* @return {W} The wrapped overder node
*/
public get overChild() {
return this.childNodes[(this.node as MmlMunderover).over];
}
/*
* Needed for movablelimits
*
* @override
*/
public get subChild() {
return this.underChild;
}
/*
* Needed for movablelimits
*
* @override
*/
public get supChild() {
return this.overChild;
}
/**
* @override
* @constructor
*/
constructor(...args: any[]) {
super(...args);
this.stretchChildren();
}
/**
* @override
*/
public computeBBox(bbox: BBox) {
if (this.hasMovableLimits()) {
super.computeBBox(bbox);
return;
}
bbox.empty();
const overbox = this.overChild.getOuterBBox();
const basebox = this.baseChild.getOuterBBox();
const underbox = this.underChild.getOuterBBox();
if (this.node.attributes.get('accent')) {
basebox.h = Math.max(basebox.h, this.font.params.x_height * basebox.scale);
}
const u = this.getOverKU(basebox, overbox)[1];
const v = this.getUnderKV(basebox, underbox)[1];
const delta = this.getDelta();
const [bw, uw, ow] = this.getDeltaW([basebox, underbox, overbox],
[0, this.isLineBelow ? 0 : -delta, this.isLineAbove ? 0 : delta]);
bbox.combine(basebox, bw, 0);
bbox.combine(overbox, ow, u);
bbox.combine(underbox, uw, v);
const z = this.font.params.big_op_spacing5;
bbox.h += z;
bbox.d += z;
bbox.clean();
}
};
}
+709
View File
@@ -0,0 +1,709 @@
/*************************************************************
*
* Copyright (c) 2017-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview Implements the a base mixin for CommonMsubsup, CommonMunderover
* and their relatives. (Since munderover can become msubsup
* when movablelimits is set, munderover needs to be able to
* do the same thing as msubsup in some cases.)
*
* @author dpvc@mathjax.org (Davide Cervone)
*/
import {AnyWrapper, WrapperConstructor, Constructor, AnyWrapperClass} from '../Wrapper.js';
import {CommonMo} from './mo.js';
import {CommonMunderover} from './munderover.js';
import {TEXCLASS} from '../../../core/MmlTree/MmlNode.js';
import {MmlMsubsup} from '../../../core/MmlTree/MmlNodes/msubsup.js';
import {MmlMo} from '../../../core/MmlTree/MmlNodes/mo.js';
import {BBox} from '../../../util/BBox.js';
import {DIRECTION} from '../FontData.js';
/*****************************************************************/
/**
* The CommonScriptbase interface
*
* @template W The child-node Wrapper class
*/
export interface CommonScriptbase<W extends AnyWrapper> extends AnyWrapper {
/**
* The core mi or mo of the base (or the base itself if there isn't one)
*/
readonly baseCore: W;
/**
* The base element's wrapper
*/
readonly baseChild: W;
/**
* The relative scaling of the base compared to the munderover/msubsup
*/
readonly baseScale: number;
/**
* The italic correction of the base (if any)
*/
readonly baseIc: number;
/**
* True if base italic correction should be removed (msub and msubsup or mathaccents)
*/
readonly baseRemoveIc: boolean;
/**
* True if the base is a single character
*/
readonly baseIsChar: boolean;
/**
* True if the base has an accent under or over
*/
readonly baseHasAccentOver: boolean;
readonly baseHasAccentUnder: boolean;
/**
* True if this is an overline or underline
*/
readonly isLineAbove: boolean;
readonly isLineBelow: boolean;
/**
* True if this is an msup with script that is a math accent
*/
readonly isMathAccent: boolean;
/**
* The script element's wrapper (overridden in subclasses)
*/
readonly scriptChild: W;
/***************************************************************************/
/*
* Methods for information about the core element for the base
*/
/**
* @return {W} The wrapper for the base core mi or mo (or whatever)
*/
getBaseCore(): W;
/**
* @return {W} The base fence item or null
*/
getSemanticBase(): W;
/**
* Recursively retrieves an element for a given fencepointer.
*
* @param {W} fence The potential fence.
* @param {string} id The fencepointer id.
* @return {W} The original fence the scripts belong to.
*/
getBaseFence(fence: W, id: string): W;
/**
* @return {number} The scaling factor for the base core relative to the munderover/msubsup
*/
getBaseScale(): number;
/**
* The base's italic correction (properly scaled)
*/
getBaseIc(): number;
/**
* An adjusted italic correction (for slightly better results)
*/
getAdjustedIc(): number;
/**
* @return {boolean} True if the base is an mi, mn, or mo (not a largeop) consisting of
* a single unstretched character
*/
isCharBase(): boolean;
/**
* Determine if the under- and overscripts are under- or overlines.
*/
checkLineAccents(): void;
/**
* @param {W} script The script node to check for being a line
*/
isLineAccent(script: W): boolean;
/***************************************************************************/
/*
* Methods for sub-sup nodes
*/
/**
* @return {number} The base child's width without the base italic correction (if not needed)
*/
getBaseWidth(): number;
/**
* Get the shift for the script (implemented in subclasses)
*
* @return {number[]} The horizontal and vertical offsets for the script
*/
getOffset(): number[];
/**
* @param {number} n The value to use if the base isn't a (non-large-op, unstretched) char
* @return {number} Either n or 0
*/
baseCharZero(n: number): number;
/**
* Get the shift for a subscript (TeXBook Appendix G 18ab)
*
* @return {number} The vertical offset for the script
*/
getV(): number;
/**
* Get the shift for a superscript (TeXBook Appendix G 18acd)
*
* @return {number} The vertical offset for the script
*/
getU(): number;
/***************************************************************************/
/*
* Methods for under-over nodes
*/
/**
* @return {boolean} True if the base has movablelimits (needed by munderover)
*/
hasMovableLimits(): boolean;
/**
* Get the separation and offset for overscripts (TeXBoox Appendix G 13, 13a)
*
* @param {BBox} basebox The bounding box of the base
* @param {BBox} overbox The bounding box of the overscript
* @return {number[]} The separation between their boxes, and the offset of the overscript
*/
getOverKU(basebox: BBox, overbox: BBox): number[];
/**
* Get the separation and offset for underscripts (TeXBoox Appendix G 13, 13a)
*
* @param {BBox} basebox The bounding box of the base
* @param {BBox} underbox The bounding box of the underscript
* @return {number[]} The separation between their boxes, and the offset of the underscript
*/
getUnderKV(basebox: BBox, underbox: BBox): number[];
/**
* @param {BBox[]} boxes The bounding boxes whose offsets are to be computed
* @param {number[]=} delta The initial x offsets of the boxes
* @return {number[]} The actual offsets needed to center the boxes in the stack
*/
getDeltaW(boxes: BBox[], delta?: number[]): number[];
/**
* @param {boolean=} noskew Whether to ignore the skew amount
* @return {number} The offset for under and over
*/
getDelta(noskew?: boolean): number;
/**
* Handle horizontal stretching of children to match greatest width
* of all children
*/
stretchChildren(): void;
}
export interface CommonScriptbaseClass extends AnyWrapperClass {
/**
* Set to true for munderover/munder/mover/msup (Appendix G 13)
*/
useIC: boolean;
}
/**
* Shorthand for the CommonScriptbase constructor
*
* @template W The child-node Wrapper class
*/
export type ScriptbaseConstructor<W extends AnyWrapper> = Constructor<CommonScriptbase<W>>;
/*****************************************************************/
/**
* A base class for msup/msub/msubsup and munder/mover/munderover
* wrapper mixin implementations
*
* @template W The child-node Wrapper class
* @template T The Wrapper class constructor type
*/
export function CommonScriptbaseMixin<
W extends AnyWrapper,
T extends WrapperConstructor
>(Base: T): ScriptbaseConstructor<W> & T {
return class extends Base {
/**
* Set to false for msubsup/msub (Appendix G 13)
*/
public static useIC: boolean = true;
/**
* The core mi or mo of the base (or the base itself if there isn't one)
*/
public baseCore: W;
/**
* The base element's wrapper
*/
public baseScale: number = 1;
/**
* The relative scaling of the base compared to the munderover/msubsup
*/
public baseIc: number = 0;
/**
* True if base italic correction should be removed (msub and msubsup or mathaccents)
*/
public baseRemoveIc: boolean = false;
/**
* True if the base is a single character
*/
public baseIsChar: boolean = false;
/**
* True if the base has an accent under or over
*/
public baseHasAccentOver: boolean = null;
public baseHasAccentUnder: boolean = null;
/**
* True if this is an overline or underline
*/
public isLineAbove: boolean = false;
public isLineBelow: boolean = false;
/**
* True if this is an msup with script that is a math accent
*/
public isMathAccent: boolean = false;
/**
* @return {W} The base element's wrapper
*/
public get baseChild(): W {
return this.childNodes[(this.node as MmlMsubsup).base];
}
/**
* @return {W} The script element's wrapper (overridden in subclasses)
*/
public get scriptChild(): W {
return this.childNodes[1];
}
/**
* @override
*/
constructor(...args: any[]) {
super(...args);
//
// Find the base core
//
const core = this.baseCore = this.getBaseCore();
if (!core) return;
//
// Get information about the base element
//
this.setBaseAccentsFor(core);
this.baseScale = this.getBaseScale();
this.baseIc = this.getBaseIc();
this.baseIsChar = this.isCharBase();
//
// Determine if we are setting a mathaccent
//
this.isMathAccent = this.baseIsChar &&
(this.scriptChild && !!this.scriptChild.coreMO().node.getProperty('mathaccent')) as boolean;
//
// Check for overline/underline accents
//
this.checkLineAccents();
//
// Check if the base is a mi or mo that needs italic correction removed
//
this.baseRemoveIc = !this.isLineAbove && !this.isLineBelow &&
(!(this.constructor as CommonScriptbaseClass).useIC || this.isMathAccent);
}
/***************************************************************************/
/*
* Methods for information about the core element for the base
*/
/**
* @return {W} The wrapper for the base core mi or mo (or whatever)
*/
public getBaseCore(): W {
let core = this.getSemanticBase() || this.childNodes[0];
while (core &&
((core.childNodes.length === 1 &&
(core.node.isKind('mrow') ||
(core.node.isKind('TeXAtom') && core.node.texClass !== TEXCLASS.VCENTER) ||
core.node.isKind('mstyle') || core.node.isKind('mpadded') ||
core.node.isKind('mphantom') || core.node.isKind('semantics'))) ||
(core.node.isKind('munderover') && core.isMathAccent))) {
this.setBaseAccentsFor(core);
core = core.childNodes[0];
}
if (!core) {
this.baseHasAccentOver = this.baseHasAccentUnder = false;
}
return core || this.childNodes[0];
}
/**
* @param {W} core The element to check for accents
*/
public setBaseAccentsFor(core: W) {
if (core.node.isKind('munderover')) {
if (this.baseHasAccentOver === null) {
this.baseHasAccentOver = !!core.node.attributes.get('accent');
}
if (this.baseHasAccentUnder === null) {
this.baseHasAccentUnder = !!core.node.attributes.get('accentunder');
}
}
}
/**
* @return {W} The base fence item or null
*/
public getSemanticBase(): W {
let fence = this.node.attributes.getExplicit('data-semantic-fencepointer') as string;
return this.getBaseFence(this.baseChild, fence);
}
/**
* Recursively retrieves an element for a given fencepointer.
*
* @param {W} fence The potential fence.
* @param {string} id The fencepointer id.
* @return {W} The original fence the scripts belong to.
*/
public getBaseFence(fence: W, id: string): W {
if (!fence || !fence.node.attributes || !id) {
return null;
}
if (fence.node.attributes.getExplicit('data-semantic-id') === id) {
return fence;
}
for (const child of fence.childNodes) {
const result = this.getBaseFence(child, id);
if (result) {
return result;
}
}
return null;
}
/**
* @return {number} The scaling factor for the base core relative to the munderover/msubsup
*/
public getBaseScale(): number {
let child = this.baseCore as any;
let scale = 1;
while (child && child !== this) {
const bbox = child.getOuterBBox();
scale *= bbox.rscale;
child = child.parent;
}
return scale;
}
/**
* The base's italic correction (properly scaled)
*/
public getBaseIc(): number {
return this.baseCore.getOuterBBox().ic * this.baseScale;
}
/**
* An adjusted italic correction (for slightly better results)
*/
public getAdjustedIc(): number {
const bbox = this.baseCore.getOuterBBox();
return (bbox.ic ? 1.05 * bbox.ic + .05 : 0) * this.baseScale;
}
/**
* @return {boolean} True if the base is an mi, mn, or mo consisting of a single character
*/
public isCharBase(): boolean {
let base = this.baseCore;
return (((base.node.isKind('mo') && (base as any).size === null) ||
base.node.isKind('mi') || base.node.isKind('mn')) &&
base.bbox.rscale === 1 && Array.from(base.getText()).length === 1);
}
/**
* Determine if the under- and overscripts are under- or overlines.
*/
public checkLineAccents() {
if (!this.node.isKind('munderover')) return;
if (this.node.isKind('mover')) {
this.isLineAbove = this.isLineAccent(this.scriptChild);
} else if (this.node.isKind('munder')) {
this.isLineBelow = this.isLineAccent(this.scriptChild);
} else {
const mml = this as unknown as CommonMunderover<W>;
this.isLineAbove = this.isLineAccent(mml.overChild);
this.isLineBelow = this.isLineAccent(mml.underChild);
}
}
/**
* @param {W} script The script node to check for being a line
* @return {boolean} True if the script is U+2015
*/
public isLineAccent(script: W): boolean {
const node = script.coreMO().node;
return (node.isToken && (node as MmlMo).getText() === '\u2015');
}
/***************************************************************************/
/*
* Methods for sub-sup nodes
*/
/**
* @return {number} The base child's width without the base italic correction (if not needed)
*/
public getBaseWidth(): number {
const bbox = this.baseChild.getOuterBBox();
return bbox.w * bbox.rscale - (this.baseRemoveIc ? this.baseIc : 0) + this.font.params.extra_ic;
}
/**
* This gives the common bbox for msub and msup. It is overridden
* for all the others (msubsup, munder, mover, munderover).
*
* @override
*/
public computeBBox(bbox: BBox, recompute: boolean = false) {
const w = this.getBaseWidth();
const [x, y] = this.getOffset();
bbox.append(this.baseChild.getOuterBBox());
bbox.combine(this.scriptChild.getOuterBBox(), w + x, y);
bbox.w += this.font.params.scriptspace;
bbox.clean();
this.setChildPWidths(recompute);
}
/**
* Get the shift for the script (implemented in subclasses)
*
* @return {[number, number]} The horizontal and vertical offsets for the script
*/
public getOffset(): [number, number] {
return [0, 0];
}
/**
* @param {number} n The value to use if the base isn't a (non-large-op, unstretched) char
* @return {number} Either n or 0
*/
public baseCharZero(n: number): number {
const largeop = !!this.baseCore.node.attributes.get('largeop');
const scale = this.baseScale;
return (this.baseIsChar && !largeop && scale === 1 ? 0 : n);
}
/**
* Get the shift for a subscript (TeXBook Appendix G 18ab)
*
* @return {number} The vertical offset for the script
*/
public getV(): number {
const bbox = this.baseCore.getOuterBBox();
const sbox = this.scriptChild.getOuterBBox();
const tex = this.font.params;
const subscriptshift = this.length2em(this.node.attributes.get('subscriptshift'), tex.sub1);
return Math.max(
this.baseCharZero(bbox.d * this.baseScale + tex.sub_drop * sbox.rscale),
subscriptshift,
sbox.h * sbox.rscale - (4 / 5) * tex.x_height
);
}
/**
* Get the shift for a superscript (TeXBook Appendix G 18acd)
*
* @return {number} The vertical offset for the script
*/
public getU(): number {
const bbox = this.baseCore.getOuterBBox();
const sbox = this.scriptChild.getOuterBBox();
const tex = this.font.params;
const attr = this.node.attributes.getList('displaystyle', 'superscriptshift');
const prime = this.node.getProperty('texprimestyle');
const p = prime ? tex.sup3 : (attr.displaystyle ? tex.sup1 : tex.sup2);
const superscriptshift = this.length2em(attr.superscriptshift, p);
return Math.max(
this.baseCharZero(bbox.h * this.baseScale - tex.sup_drop * sbox.rscale),
superscriptshift,
sbox.d * sbox.rscale + (1 / 4) * tex.x_height
);
}
/***************************************************************************/
/*
* Methods for under-over nodes
*/
/**
* @return {boolean} True if the base has movablelimits (needed by munderover)
*/
public hasMovableLimits(): boolean {
const display = this.node.attributes.get('displaystyle');
const mo = this.baseChild.coreMO().node;
return (!display && !!mo.attributes.get('movablelimits'));
}
/**
* Get the separation and offset for overscripts (TeXBoox Appendix G 13, 13a)
*
* @param {BBox} basebox The bounding box of the base
* @param {BBox} overbox The bounding box of the overscript
* @return {[number, number]} The separation between their boxes, and the offset of the overscript
*/
public getOverKU(basebox: BBox, overbox: BBox): [number, number] {
const accent = this.node.attributes.get('accent') as boolean;
const tex = this.font.params;
const d = overbox.d * overbox.rscale;
const t = tex.rule_thickness * tex.separation_factor;
const delta = (this.baseHasAccentOver ? t : 0);
const T = (this.isLineAbove ? 3 * tex.rule_thickness : t);
const k = (accent ? T : Math.max(tex.big_op_spacing1, tex.big_op_spacing3 - Math.max(0, d))) - delta;
return [k, basebox.h * basebox.rscale + k + d];
}
/**
* Get the separation and offset for underscripts (TeXBoox Appendix G 13, 13a)
*
* @param {BBox} basebox The bounding box of the base
* @param {BBox} underbox The bounding box of the underscript
* @return {[number, number]} The separation between their boxes, and the offset of the underscript
*/
public getUnderKV(basebox: BBox, underbox: BBox): [number, number] {
const accent = this.node.attributes.get('accentunder') as boolean;
const tex = this.font.params;
const h = underbox.h * underbox.rscale;
const t = tex.rule_thickness * tex.separation_factor;
const delta = (this.baseHasAccentUnder ? t : 0);
const T = (this.isLineBelow ? 3 * tex.rule_thickness : t);
const k = (accent ? T : Math.max(tex.big_op_spacing2, tex.big_op_spacing4 - h)) - delta;
return [k, -(basebox.d * basebox.rscale + k + h)];
}
/**
* @param {BBox[]} boxes The bounding boxes whose offsets are to be computed
* @param {number[]=} delta The initial x offsets of the boxes
* @return {number[]} The actual offsets needed to center the boxes in the stack
*/
public getDeltaW(boxes: BBox[], delta: number[] = [0, 0, 0]): number[] {
const align = this.node.attributes.get('align');
const widths = boxes.map(box => box.w * box.rscale);
widths[0] -= (this.baseRemoveIc && !this.baseCore.node.attributes.get('largeop') ? this.baseIc : 0);
const w = Math.max(...widths);
const dw = [] as number[];
let m = 0;
for (const i of widths.keys()) {
dw[i] = (align === 'center' ? (w - widths[i]) / 2 :
align === 'right' ? w - widths[i] : 0) + delta[i];
if (dw[i] < m) {
m = -dw[i];
}
}
if (m) {
for (const i of dw.keys()) {
dw[i] += m;
}
}
[1, 2].map(i => dw[i] += (boxes[i] ? boxes[i].dx * boxes[0].scale : 0));
return dw;
}
/**
* @param {boolean=} noskew Whether to ignore the skew amount
* @return {number} The offset for under and over
*/
public getDelta(noskew: boolean = false): number {
const accent = this.node.attributes.get('accent');
const {sk, ic} = this.baseCore.getOuterBBox();
return ((accent && !noskew ? sk : 0) + this.font.skewIcFactor * ic) * this.baseScale;
}
/**
* Handle horizontal stretching of children to match greatest width
* of all children
*/
public stretchChildren() {
let stretchy: AnyWrapper[] = [];
//
// Locate and count the stretchy children
//
for (const child of this.childNodes) {
if (child.canStretch(DIRECTION.Horizontal)) {
stretchy.push(child);
}
}
let count = stretchy.length;
let nodeCount = this.childNodes.length;
if (count && nodeCount > 1) {
let W = 0;
//
// If all the children are stretchy, find the largest one,
// otherwise, find the width of the non-stretchy children.
//
let all = (count > 1 && count === nodeCount);
for (const child of this.childNodes) {
const noStretch = (child.stretch.dir === DIRECTION.None);
if (all || noStretch) {
const {w, rscale} = child.getOuterBBox(noStretch);
if (w * rscale > W) W = w * rscale;
}
}
//
// Stretch the stretchable children
//
for (const child of stretchy) {
(child.coreMO() as CommonMo).getStretchedVariant([W / child.bbox.rscale]);
}
}
}
};
}
+62
View File
@@ -0,0 +1,62 @@
/*************************************************************
*
* Copyright (c) 2017-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview Implements the CommonSemantics wrapper mixin for the MmlSemantics object
*
* @author dpvc@mathjax.org (Davide Cervone)
*/
import {AnyWrapper, WrapperConstructor, Constructor} from '../Wrapper.js';
import {BBox} from '../../../util/BBox.js';
/*****************************************************************/
/**
* The CommonSemantics interface
*/
export interface CommonSemantics extends AnyWrapper {
}
/**
* Shorthand for the CommonSemantics constructor
*/
export type SemanticsConstructor = Constructor<CommonSemantics>;
/*****************************************************************/
/**
* The CommonSemantics wrapper mixin for the MmlSemantics object
*
* @template T The Wrapper class constructor type
*/
export function CommonSemanticsMixin<T extends WrapperConstructor>(Base: T): SemanticsConstructor & T {
return class extends Base {
/**
* @override
*/
public computeBBox(bbox: BBox, _recompute: boolean = false) {
if (this.childNodes.length) {
const {w, h, d} = this.childNodes[0].getBBox();
bbox.w = w;
bbox.h = h;
bbox.d = d;
}
}
};
}
+101
View File
@@ -0,0 +1,101 @@
/*************************************************************
*
* Copyright (c) 2017-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview The MathJax TeXFont object
*
* @author dpvc@mathjax.org (Davide Cervone)
*/
import {FontDataClass, CharOptions, VariantData, DelimiterData, CssFontMap} from '../FontData.js';
/*****************************************************************/
/**
* The CommonTeXFont mixin for the CommonTeXFont object
*
* @template C The CharOptions class for this font
* @template V The VariantData class for this font
* @template B The FontData class to extend
*/
export function CommonTeXFontMixin<
C extends CharOptions,
V extends VariantData<C>,
D extends DelimiterData,
B extends FontDataClass<C, V, D>
>(Base: B): FontDataClass<C, V, D> & B {
return class extends Base {
/**
* @override
*/
public static NAME = 'TeX';
/**
* Add the extra variants for the TeX fonts
*/
protected static defaultVariants = [
...Base.defaultVariants,
['-smallop', 'normal'],
['-largeop', 'normal'],
['-size3', 'normal'],
['-size4', 'normal'],
['-tex-calligraphic', 'italic'],
['-tex-bold-calligraphic', 'bold-italic'],
['-tex-oldstyle', 'normal'],
['-tex-bold-oldstyle', 'bold'],
['-tex-mathit', 'italic'],
['-tex-variant', 'normal']
];
/**
* The data used for CSS for undefined characters for each variant
*/
protected static defaultCssFonts: CssFontMap = {
...Base.defaultCssFonts,
'-smallop': ['serif', false, false],
'-largeop': ['serif', false, false],
'-size3': ['serif', false, false],
'-size4': ['serif', false, false],
'-tex-calligraphic': ['cursive', true, false],
'-tex-bold-calligraphic': ['cursive', true, true],
'-tex-oldstyle': ['serif', false, false],
'-tex-bold-oldstyle': ['serif', false, true],
'-tex-mathit': ['serif', true, false]
};
/**
* The default variants for the standard stretchy sizes
*/
protected static defaultSizeVariants = ['normal', '-smallop', '-largeop', '-size3', '-size4', '-tex-variant'];
/**
* The default variants for the standard stretchy assmebly parts
*/
protected static defaultStretchVariants = ['-size4'];
/**
* @override
*/
protected getDelimiterData(n: number) {
return this.getChar('-smallop', n) || this.getChar('-size4', n);
}
};
}
+27
View File
@@ -0,0 +1,27 @@
/*************************************************************
*
* Copyright (c) 2018-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import {CharMap, CharOptions} from '../../FontData.js';
export const boldItalic: CharMap<CharOptions> = {
0x2F: [.711, .21, .894],
0x131: [.452, .008, .394, {sk: .0319}],
0x237: [.451, .201, .439, {sk: .0958}],
0x2044: [.711, .21, .894],
0x2206: [.711, 0, .958, {sk: .192}],
0x29F8: [.711, .21, .894],
};
+276
View File
@@ -0,0 +1,276 @@
/*************************************************************
*
* Copyright (c) 2018-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import {CharMap, CharOptions} from '../../FontData.js';
export const bold: CharMap<CharOptions> = {
0x21: [.705, 0, .35],
0x22: [.694, -0.329, .603],
0x23: [.694, .193, .958],
0x24: [.75, .056, .575],
0x25: [.75, .056, .958],
0x26: [.705, .011, .894],
0x27: [.694, -0.329, .319],
0x28: [.75, .249, .447],
0x29: [.75, .249, .447],
0x2A: [.75, -0.306, .575],
0x2B: [.633, .131, .894],
0x2C: [.171, .194, .319],
0x2D: [.278, -0.166, .383],
0x2E: [.171, 0, .319],
0x2F: [.75, .25, .575],
0x3A: [.444, 0, .319],
0x3B: [.444, .194, .319],
0x3C: [.587, .085, .894],
0x3D: [.393, -0.109, .894],
0x3E: [.587, .085, .894],
0x3F: [.7, 0, .543],
0x40: [.699, .006, .894],
0x5B: [.75, .25, .319],
0x5C: [.75, .25, .575],
0x5D: [.75, .25, .319],
0x5E: [.694, -0.52, .575],
0x5F: [-0.01, .061, .575],
0x60: [.706, -0.503, .575],
0x7B: [.75, .25, .575],
0x7C: [.75, .249, .319],
0x7D: [.75, .25, .575],
0x7E: [.344, -0.202, .575],
0xA8: [.695, -0.535, .575],
0xAC: [.371, -0.061, .767],
0xAF: [.607, -0.54, .575],
0xB0: [.702, -0.536, .575],
0xB1: [.728, .035, .894],
0xB4: [.706, -0.503, .575],
0xB7: [.336, -0.166, .319],
0xD7: [.53, .028, .894],
0xF7: [.597, .096, .894],
0x131: [.442, 0, .278, {sk: .0278}],
0x237: [.442, .205, .306, {sk: .0833}],
0x2B9: [.563, -0.033, .344],
0x2C6: [.694, -0.52, .575],
0x2C7: [.66, -0.515, .575],
0x2C9: [.607, -0.54, .575],
0x2CA: [.706, -0.503, .575],
0x2CB: [.706, -0.503, .575],
0x2D8: [.694, -0.5, .575],
0x2D9: [.695, -0.525, .575],
0x2DA: [.702, -0.536, .575],
0x2DC: [.694, -0.552, .575],
0x300: [.706, -0.503, 0],
0x301: [.706, -0.503, 0],
0x302: [.694, -0.52, 0],
0x303: [.694, -0.552, 0],
0x304: [.607, -0.54, 0],
0x306: [.694, -0.5, 0],
0x307: [.695, -0.525, 0],
0x308: [.695, -0.535, 0],
0x30A: [.702, -0.536, 0],
0x30B: [.714, -0.511, 0],
0x30C: [.66, -0.515, 0],
0x338: [.711, .21, 0],
0x2002: [0, 0, .5],
0x2003: [0, 0, .999],
0x2004: [0, 0, .333],
0x2005: [0, 0, .25],
0x2006: [0, 0, .167],
0x2009: [0, 0, .167],
0x200A: [0, 0, .083],
0x2013: [.3, -0.249, .575],
0x2014: [.3, -0.249, 1.15],
0x2015: [.3, -0.249, 1.15],
0x2016: [.75, .248, .575],
0x2017: [-0.01, .061, .575],
0x2018: [.694, -0.329, .319],
0x2019: [.694, -0.329, .319],
0x201C: [.694, -0.329, .603],
0x201D: [.694, -0.329, .603],
0x2020: [.702, .211, .511],
0x2021: [.702, .202, .511],
0x2022: [.474, -0.028, .575],
0x2026: [.171, 0, 1.295],
0x2032: [.563, -0.033, .344],
0x2033: [.563, 0, .688],
0x2034: [.563, 0, 1.032],
0x203E: [.607, -0.54, .575],
0x2044: [.75, .25, .575],
0x2057: [.563, 0, 1.376],
0x20D7: [.723, -0.513, .575],
0x210F: [.694, .008, .668, {sk: -0.0319}],
0x2113: [.702, .019, .474, {sk: .128}],
0x2118: [.461, .21, .74],
0x2135: [.694, 0, .703],
0x2190: [.518, .017, 1.15],
0x2191: [.694, .193, .575],
0x2192: [.518, .017, 1.15],
0x2193: [.694, .194, .575],
0x2194: [.518, .017, 1.15],
0x2195: [.767, .267, .575],
0x2196: [.724, .194, 1.15],
0x2197: [.724, .193, 1.15],
0x2198: [.694, .224, 1.15],
0x2199: [.694, .224, 1.15],
0x219A: [.711, .21, 1.15],
0x219B: [.711, .21, 1.15],
0x21A6: [.518, .017, 1.15],
0x21A9: [.518, .017, 1.282],
0x21AA: [.518, .017, 1.282],
0x21AE: [.711, .21, 1.15],
0x21BC: [.518, -0.22, 1.15],
0x21BD: [.281, .017, 1.15],
0x21C0: [.518, -0.22, 1.15],
0x21C1: [.281, .017, 1.15],
0x21CC: [.718, .017, 1.15],
0x21CD: [.711, .21, 1.15],
0x21CE: [.711, .21, 1.15],
0x21CF: [.711, .21, 1.15],
0x21D0: [.547, .046, 1.15],
0x21D1: [.694, .193, .703],
0x21D2: [.547, .046, 1.15],
0x21D3: [.694, .194, .703],
0x21D4: [.547, .046, 1.15],
0x21D5: [.767, .267, .703],
0x2200: [.694, .016, .639],
0x2203: [.694, 0, .639],
0x2204: [.711, .21, .639],
0x2205: [.767, .073, .575],
0x2206: [.698, 0, .958],
0x2208: [.587, .086, .767],
0x2209: [.711, .21, .767],
0x220B: [.587, .086, .767],
0x220C: [.711, .21, .767],
0x2212: [.281, -0.221, .894],
0x2213: [.537, .227, .894],
0x2215: [.75, .25, .575],
0x2216: [.75, .25, .575],
0x2217: [.472, -0.028, .575],
0x2218: [.474, -0.028, .575],
0x2219: [.474, -0.028, .575],
0x221A: [.82, .18, .958, {ic: .03}],
0x221D: [.451, .008, .894],
0x221E: [.452, .008, 1.15],
0x2220: [.714, 0, .722],
0x2223: [.75, .249, .319],
0x2224: [.75, .249, .319],
0x2225: [.75, .248, .575],
0x2226: [.75, .248, .575],
0x2227: [.604, .017, .767],
0x2228: [.604, .016, .767],
0x2229: [.603, .016, .767],
0x222A: [.604, .016, .767],
0x222B: [.711, .211, .569, {ic: .063}],
0x223C: [.391, -0.109, .894],
0x2240: [.583, .082, .319],
0x2241: [.711, .21, .894],
0x2243: [.502, 0, .894],
0x2244: [.711, .21, .894],
0x2245: [.638, .027, .894],
0x2247: [.711, .21, .894],
0x2248: [.524, -0.032, .894],
0x2249: [.711, .21, .894],
0x224D: [.533, .032, .894],
0x2250: [.721, -0.109, .894],
0x2260: [.711, .21, .894],
0x2261: [.505, 0, .894],
0x2262: [.711, .21, .894],
0x2264: [.697, .199, .894],
0x2265: [.697, .199, .894],
0x226A: [.617, .116, 1.15],
0x226B: [.618, .116, 1.15],
0x226D: [.711, .21, .894],
0x226E: [.711, .21, .894],
0x226F: [.711, .21, .894],
0x2270: [.711, .21, .894],
0x2271: [.711, .21, .894],
0x227A: [.585, .086, .894],
0x227B: [.586, .086, .894],
0x2280: [.711, .21, .894],
0x2281: [.711, .21, .894],
0x2282: [.587, .085, .894],
0x2283: [.587, .086, .894],
0x2284: [.711, .21, .894],
0x2285: [.711, .21, .894],
0x2286: [.697, .199, .894],
0x2287: [.697, .199, .894],
0x2288: [.711, .21, .894],
0x2289: [.711, .21, .894],
0x228E: [.604, .016, .767],
0x2291: [.697, .199, .894],
0x2292: [.697, .199, .894],
0x2293: [.604, 0, .767],
0x2294: [.604, 0, .767],
0x2295: [.632, .132, .894],
0x2296: [.632, .132, .894],
0x2297: [.632, .132, .894],
0x2298: [.632, .132, .894],
0x2299: [.632, .132, .894],
0x22A2: [.693, 0, .703],
0x22A3: [.693, 0, .703],
0x22A4: [.694, 0, .894],
0x22A5: [.693, 0, .894],
0x22A8: [.75, .249, .974],
0x22AC: [.711, .21, .703],
0x22AD: [.75, .249, .974],
0x22C4: [.523, .021, .575],
0x22C5: [.336, -0.166, .319],
0x22C6: [.502, 0, .575],
0x22C8: [.54, .039, 1],
0x22E2: [.711, .21, .894],
0x22E3: [.711, .21, .894],
0x22EE: [.951, .029, .319],
0x22EF: [.336, -0.166, 1.295],
0x22F1: [.871, -0.101, 1.323],
0x2308: [.75, .248, .511],
0x2309: [.75, .248, .511],
0x230A: [.749, .248, .511],
0x230B: [.749, .248, .511],
0x2322: [.405, -0.108, 1.15],
0x2323: [.392, -0.126, 1.15],
0x2329: [.75, .249, .447],
0x232A: [.75, .249, .447],
0x25B3: [.711, 0, 1.022],
0x25B5: [.711, 0, 1.022],
0x25B9: [.54, .039, .575],
0x25BD: [.5, .21, 1.022],
0x25BF: [.5, .21, 1.022],
0x25C3: [.539, .038, .575],
0x25EF: [.711, .211, 1.15],
0x2660: [.719, .129, .894],
0x2661: [.711, .024, .894],
0x2662: [.719, .154, .894],
0x2663: [.719, .129, .894],
0x266D: [.75, .017, .447],
0x266E: [.741, .223, .447],
0x266F: [.724, .224, .447],
0x2758: [.75, .249, .319],
0x27E8: [.75, .249, .447],
0x27E9: [.75, .249, .447],
0x27F5: [.518, .017, 1.805],
0x27F6: [.518, .017, 1.833],
0x27F7: [.518, .017, 2.126],
0x27F8: [.547, .046, 1.868],
0x27F9: [.547, .046, 1.87],
0x27FA: [.547, .046, 2.126],
0x27FC: [.518, .017, 1.833],
0x29F8: [.711, .21, .894],
0x2A2F: [.53, .028, .894],
0x2A3F: [.686, 0, .9],
0x2AAF: [.696, .199, .894],
0x2AB0: [.697, .199, .894],
0x3008: [.75, .249, .447],
0x3009: [.75, .249, .447],
};
+172
View File
@@ -0,0 +1,172 @@
/*************************************************************
*
* Copyright (c) 2018-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import {DelimiterMap, DelimiterData, V, H} from '../../FontData.js';
export const HDW1 = [.75, .25, .875];
export const HDW2 = [.85, .349, .667];
export const HDW3 = [.583, .082, .5];
export const VSIZES = [1, 1.2, 1.8, 2.4, 3];
const DELIM2F = {c: 0x2F, dir: V, sizes: VSIZES};
const DELIMAF = {c: 0xAF, dir: H, sizes: [.5], stretch: [0, 0xAF], HDW: [.59, -0.544, .5]};
const DELIM2C6 = {c: 0x2C6, dir: H, sizes: [.5, .556, 1, 1.444, 1.889]};
const DELIM2DC = {c: 0x2DC, dir: H, sizes: [.5, .556, 1, 1.444, 1.889]};
const DELIM2013 = {c: 0x2013, dir: H, sizes: [.5], stretch: [0, 0x2013], HDW: [.285, -0.248, .5]};
const DELIM2190 = {c: 0x2190, dir: H, sizes: [1], stretch: [0x2190, 0x2212], HDW: HDW3};
const DELIM2192 = {c: 0x2192, dir: H, sizes: [1], stretch: [0, 0x2212, 0x2192], HDW: HDW3};
const DELIM2194 = {c: 0x2194, dir: H, sizes: [1], stretch: [0x2190, 0x2212, 0x2192], HDW: HDW3};
const DELIM21A4 = {c: 0x21A4, dir: H, stretch: [0x2190, 0x2212, 0x2223], HDW: HDW3, min: 1.278};
const DELIM21A6 = {c: 0x21A6, dir: H, sizes: [1], stretch: [0x2223, 0x2212, 0x2192], HDW: HDW3};
const DELIM21D0 = {c: 0x21D0, dir: H, sizes: [1], stretch: [0x21D0, 0x3D], HDW: HDW3};
const DELIM21D2 = {c: 0x21D2, dir: H, sizes: [1], stretch: [0, 0x3D, 0x21D2], HDW: HDW3};
const DELIM21D4 = {c: 0x21D4, dir: H, sizes: [1], stretch: [0x21D0, 0x3D, 0x21D2], HDW: HDW3};
const DELIM2212 = {c: 0x2212, dir: H, sizes: [.778], stretch: [0, 0x2212], HDW: HDW3};
const DELIM2223 = {c: 0x2223, dir: V, sizes: [1], stretch: [0, 0x2223], HDW: [.627, .015, .333]};
const DELIM23DC = {c: 0x23DC, dir: H, sizes: [.778, 1], schar: [0x2322, 0x2322], variants: [5, 0],
stretch: [0xE150, 0xE154, 0xE151], HDW: [.32, .2, .5]};
const DELIM23DD = {c: 0x23DD, dir: H, sizes: [.778, 1], schar: [0x2323, 0x2323], variants: [5, 0],
stretch: [0xE152, 0xE154, 0xE153], HDW: [.32, .2, .5]};
const DELIM23DE = {c: 0x23DE, dir: H, stretch: [0xE150, 0xE154, 0xE151, 0xE155], HDW: [.32, .2, .5], min: 1.8};
const DELIM23DF = {c: 0x23DF, dir: H, stretch: [0xE152, 0xE154, 0xE153, 0xE156], HDW: [.32, .2, .5], min: 1.8};
const DELIM27E8 = {c: 0x27E8, dir: V, sizes: VSIZES};
const DELIM27E9 = {c: 0x27E9, dir: V, sizes: VSIZES};
const DELIM2906 = {c: 0x2906, dir: H, stretch: [0x21D0, 0x3D, 0x2223], HDW: HDW3, min: 1.278};
const DELIM2907 = {c: 0x2907, dir: H, stretch: [0x22A8, 0x3D, 0x21D2], HDW: HDW3, min: 1.278};
export const delimiters: DelimiterMap<DelimiterData> = {
0x28: {dir: V, sizes: VSIZES, stretch: [0x239B, 0x239C, 0x239D], HDW: [.85, .349, .875]},
0x29: {dir: V, sizes: VSIZES, stretch: [0x239E, 0x239F, 0x23A0], HDW: [.85, .349, .875]},
0x2D: DELIM2212,
0x2F: DELIM2F,
0x3D: {dir: H, sizes: [.778], stretch: [0, 0x3D], HDW: HDW3},
0x5B: {dir: V, sizes: VSIZES, stretch: [0x23A1, 0x23A2, 0x23A3], HDW: HDW2},
0x5C: {dir: V, sizes: VSIZES},
0x5D: {dir: V, sizes: VSIZES, stretch: [0x23A4, 0x23A5, 0x23A6], HDW: HDW2},
0x5E: DELIM2C6,
0x5F: DELIM2013,
0x7B: {dir: V, sizes: VSIZES, stretch: [0x23A7, 0x23AA, 0x23A9, 0x23A8], HDW: [.85, .349, .889]},
0x7C: {dir: V, sizes: [1], stretch: [0, 0x2223], HDW: [.75, .25, .333]},
0x7D: {dir: V, sizes: VSIZES, stretch: [0x23AB, 0x23AA, 0x23AD, 0x23AC], HDW: [.85, .349, .889]},
0x7E: DELIM2DC,
0xAF: DELIMAF,
0x2C6: DELIM2C6,
0x2C9: DELIMAF,
0x2DC: DELIM2DC,
0x302: DELIM2C6,
0x303: DELIM2DC,
0x332: DELIM2013,
0x2013: DELIM2013,
0x2014: DELIM2013,
0x2015: DELIM2013,
0x2016: {dir: V, sizes: [.602, 1], schar: [0, 0x2225], variants: [1, 0], stretch: [0, 0x2225], HDW: [.602, 0, .556]},
0x2017: DELIM2013,
0x203E: DELIMAF,
0x20D7: DELIM2192,
0x2190: DELIM2190,
0x2191: {dir: V, sizes: [.888], stretch: [0x2191, 0x23D0], HDW: [.6, 0, .667]},
0x2192: DELIM2192,
0x2193: {dir: V, sizes: [.888], stretch: [0, 0x23D0, 0x2193], HDW: [.6, 0, .667]},
0x2194: DELIM2194,
0x2195: {dir: V, sizes: [1.044], stretch: [0x2191, 0x23D0, 0x2193], HDW: HDW1},
0x219E: {dir: H, sizes: [1], stretch: [0x219E, 0x2212], HDW: HDW3},
0x21A0: {dir: H, sizes: [1], stretch: [0, 0x2212, 0x21A0], HDW: HDW3},
0x21A4: DELIM21A4,
0x21A5: {dir: V, stretch: [0x2191, 0x23D0, 0x22A5], HDW: HDW1, min: 1.555},
0x21A6: DELIM21A6,
0x21A7: {dir: V, stretch: [0x22A4, 0x23D0, 0x2193], HDW: HDW1, min: 1.555},
0x21B0: {dir: V, sizes: [.722], stretch: [0x21B0, 0x23D0], HDW: HDW1},
0x21B1: {dir: V, sizes: [.722], stretch: [0x21B1, 0x23D0], HDW: HDW1},
0x21BC: {dir: H, sizes: [1], stretch: [0x21BC, 0x2212], HDW: HDW3},
0x21BD: {dir: H, sizes: [1], stretch: [0x21BD, 0x2212], HDW: HDW3},
0x21BE: {dir: V, sizes: [.888], stretch: [0x21BE, 0x23D0], HDW: HDW1},
0x21BF: {dir: V, sizes: [.888], stretch: [0x21BF, 0x23D0], HDW: HDW1},
0x21C0: {dir: H, sizes: [1], stretch: [0, 0x2212, 0x21C0], HDW: HDW3},
0x21C1: {dir: H, sizes: [1], stretch: [0, 0x2212, 0x21C1], HDW: HDW3},
0x21C2: {dir: V, sizes: [.888], stretch: [0, 0x23D0, 0x21C2], HDW: HDW1},
0x21C3: {dir: V, sizes: [.888], stretch: [0, 0x23D0, 0x21C3], HDW: HDW1},
0x21D0: DELIM21D0,
0x21D1: {dir: V, sizes: [.888], stretch: [0x21D1, 0x2016], HDW: [.599, 0, .778]},
0x21D2: DELIM21D2,
0x21D3: {dir: V, sizes: [.888], stretch: [0, 0x2016, 0x21D3], HDW: [.6, 0, .778]},
0x21D4: DELIM21D4,
0x21D5: {dir: V, sizes: [1.044], stretch: [0x21D1, 0x2016, 0x21D3], HDW: [.75, .25, .778]},
0x21DA: {dir: H, sizes: [1], stretch: [0x21DA, 0x2261], HDW: [.464, -0.036, .5]},
0x21DB: {dir: H, sizes: [1], stretch: [0, 0x2261, 0x21DB], HDW: [.464, -0.036, .5]},
0x2212: DELIM2212,
0x2215: DELIM2F,
0x221A: {dir: V, sizes: VSIZES, stretch: [0xE001, 0xE000, 0x23B7], fullExt: [.65, 2.3], HDW: [.85, .35, 1.056]},
0x2223: DELIM2223,
0x2225: {dir: V, sizes: [1], stretch: [0, 0x2225], HDW: [.627, .015, .556]},
0x2308: {dir: V, sizes: VSIZES, stretch: [0x23A1, 0x23A2], HDW: HDW2},
0x2309: {dir: V, sizes: VSIZES, stretch: [0x23A4, 0x23A5], HDW: HDW2},
0x230A: {dir: V, sizes: VSIZES, stretch: [0, 0x23A2, 0x23A3], HDW: HDW2},
0x230B: {dir: V, sizes: VSIZES, stretch: [0, 0x23A5, 0x23A6], HDW: HDW2},
0x2312: DELIM23DC,
0x2322: DELIM23DC,
0x2323: DELIM23DD,
0x2329: DELIM27E8,
0x232A: DELIM27E9,
0x23AA: {dir: V, sizes: [.32], stretch: [0x23AA, 0x23AA, 0x23AA], HDW: [.29, .015, .889]},
0x23AF: DELIM2013,
0x23B0: {dir: V, sizes: [.989], stretch: [0x23A7, 0x23AA, 0x23AD], HDW: [.75, .25, .889]},
0x23B1: {dir: V, sizes: [.989], stretch: [0x23AB, 0x23AA, 0x23A9], HDW: [.75, .25, .889]},
0x23B4: {dir: H, stretch: [0x250C, 0x2212, 0x2510], HDW: HDW3, min: 1},
0x23B5: {dir: H, stretch: [0x2514, 0x2212, 0x2518], HDW: HDW3, min: 1},
0x23D0: {dir: V, sizes: [.602, 1], schar: [0, 0x2223], variants: [1, 0], stretch: [0, 0x2223], HDW: [.602, 0, .333]},
0x23DC: DELIM23DC,
0x23DD: DELIM23DD,
0x23DE: DELIM23DE,
0x23DF: DELIM23DF,
0x23E0: {dir: H, stretch: [0x2CA, 0x2C9, 0x2CB], HDW: [.59, -0.544, .5], min: 1},
0x23E1: {dir: H, stretch: [0x2CB, 0x2C9, 0x2CA], HDW: [.59, -0.544, .5], min: 1},
0x2500: DELIM2013,
0x2758: DELIM2223,
0x27E8: DELIM27E8,
0x27E9: DELIM27E9,
0x27EE: {dir: V, sizes: [.989], stretch: [0x23A7, 0x23AA, 0x23A9], HDW: [.75, .25, .889]},
0x27EF: {dir: V, sizes: [.989], stretch: [0x23AB, 0x23AA, 0x23AD], HDW: [.75, .25, .889]},
0x27F5: DELIM2190,
0x27F6: DELIM2192,
0x27F7: DELIM2194,
0x27F8: DELIM21D0,
0x27F9: DELIM21D2,
0x27FA: DELIM21D4,
0x27FB: DELIM21A4,
0x27FC: DELIM21A6,
0x27FD: DELIM2906,
0x27FE: DELIM2907,
0x2906: DELIM2906,
0x2907: DELIM2907,
0x294E: {dir: H, stretch: [0x21BC, 0x2212, 0x21C0], HDW: HDW3, min: 2},
0x294F: {dir: V, stretch: [0x21BE, 0x23D0, 0x21C2], HDW: HDW1, min: 1.776},
0x2950: {dir: H, stretch: [0x21BD, 0x2212, 0x21C1], HDW: HDW3, min: 2},
0x2951: {dir: V, stretch: [0x21BF, 0x23D0, 0x21C3], HDW: HDW1, min: .5},
0x295A: {dir: H, stretch: [0x21BC, 0x2212, 0x2223], HDW: HDW3, min: 1.278},
0x295B: {dir: H, stretch: [0x2223, 0x2212, 0x21C0], HDW: HDW3, min: 1.278},
0x295C: {dir: V, stretch: [0x21BE, 0x23D0, 0x22A5], HDW: HDW1, min: 1.556},
0x295D: {dir: V, stretch: [0x22A4, 0x23D0, 0x21C2], HDW: HDW1, min: 1.556},
0x295E: {dir: H, stretch: [0x21BD, 0x2212, 0x2223], HDW: HDW3, min: 1.278},
0x295F: {dir: H, stretch: [0x2223, 0x2212, 0x21C1], HDW: HDW3, min: 1.278},
0x2960: {dir: V, stretch: [0x21BF, 0x23D0, 0x22A5], HDW: HDW1, min: 1.776},
0x2961: {dir: V, stretch: [0x22A4, 0x23D0, 0x21C3], HDW: HDW1, min: 1.776},
0x3008: DELIM27E8,
0x3009: DELIM27E9,
0xFE37: DELIM23DE,
0xFE38: DELIM23DF,
};
+21
View File
@@ -0,0 +1,21 @@
/*************************************************************
*
* Copyright (c) 2018-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import {CharMap, CharOptions} from '../../FontData.js';
export const doubleStruck: CharMap<CharOptions> = {
};
+60
View File
@@ -0,0 +1,60 @@
/*************************************************************
*
* Copyright (c) 2018-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import {CharMap, CharOptions} from '../../FontData.js';
export const frakturBold: CharMap<CharOptions> = {
0x21: [.689, .012, .349],
0x22: [.695, -0.432, .254],
0x26: [.696, .016, .871],
0x27: [.695, -0.436, .25],
0x28: [.737, .186, .459],
0x29: [.735, .187, .459],
0x2A: [.692, -0.449, .328],
0x2B: [.598, .082, .893],
0x2C: [.107, .191, .328],
0x2D: [.275, -0.236, .893],
0x2E: [.102, .015, .328],
0x2F: [.721, .182, .593],
0x30: [.501, .012, .593],
0x31: [.489, 0, .593],
0x32: [.491, 0, .593],
0x33: [.487, .193, .593],
0x34: [.495, .196, .593],
0x35: [.481, .19, .593],
0x36: [.704, .012, .593],
0x37: [.479, .197, .593],
0x38: [.714, .005, .593],
0x39: [.487, .195, .593],
0x3A: [.457, .012, .255],
0x3B: [.458, .19, .255],
0x3D: [.343, -0.168, .582],
0x3F: [.697, .014, .428],
0x5B: [.74, .13, .257],
0x5D: [.738, .132, .257],
0x5E: [.734, -0.452, .59],
0x2018: [.708, -0.411, .254],
0x2019: [.692, -0.394, .254],
0x2044: [.721, .182, .593],
0xE301: [.63, .027, .587],
0xE302: [.693, .212, .394, {ic: .014}],
0xE303: [.681, .219, .387],
0xE304: [.473, .212, .593],
0xE305: [.684, .027, .393],
0xE308: [.679, .22, .981],
0xE309: [.717, .137, .727],
};
+61
View File
@@ -0,0 +1,61 @@
/*************************************************************
*
* Copyright (c) 2018-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import {CharMap, CharOptions} from '../../FontData.js';
export const fraktur: CharMap<CharOptions> = {
0x21: [.689, .012, .296],
0x22: [.695, -0.432, .215],
0x26: [.698, .011, .738],
0x27: [.695, -0.436, .212],
0x28: [.737, .186, .389],
0x29: [.735, .187, .389],
0x2A: [.692, -0.449, .278],
0x2B: [.598, .082, .756],
0x2C: [.107, .191, .278],
0x2D: [.275, -0.236, .756],
0x2E: [.102, .015, .278],
0x2F: [.721, .182, .502],
0x30: [.492, .013, .502],
0x31: [.468, 0, .502],
0x32: [.474, 0, .502],
0x33: [.473, .182, .502],
0x34: [.476, .191, .502],
0x35: [.458, .184, .502],
0x36: [.7, .013, .502],
0x37: [.468, .181, .502],
0x38: [.705, .01, .502],
0x39: [.469, .182, .502],
0x3A: [.457, .012, .216],
0x3B: [.458, .189, .216],
0x3D: [.368, -0.132, .756],
0x3F: [.693, .011, .362],
0x5B: [.74, .13, .278],
0x5D: [.738, .131, .278],
0x5E: [.734, -0.452, .5],
0x2018: [.708, -0.41, .215],
0x2019: [.692, -0.395, .215],
0x2044: [.721, .182, .502],
0xE300: [.683, .032, .497],
0xE301: [.616, .03, .498],
0xE302: [.68, .215, .333],
0xE303: [.679, .224, .329],
0xE304: [.471, .214, .503],
0xE305: [.686, .02, .333],
0xE306: [.577, .021, .334, {ic: .013}],
0xE307: [.475, .022, .501, {ic: .013}],
};
+81
View File
@@ -0,0 +1,81 @@
/*************************************************************
*
* Copyright (c) 2018-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import {CharMap, CharOptions} from '../../FontData.js';
export const italic: CharMap<CharOptions> = {
0x21: [.716, 0, .307, {ic: .073}],
0x22: [.694, -0.379, .514, {ic: .024}],
0x23: [.694, .194, .818, {ic: .01}],
0x25: [.75, .056, .818, {ic: .029}],
0x26: [.716, .022, .767, {ic: .035}],
0x27: [.694, -0.379, .307, {ic: .07}],
0x28: [.75, .25, .409, {ic: .108}],
0x29: [.75, .25, .409],
0x2A: [.75, -0.32, .511, {ic: .073}],
0x2B: [.557, .057, .767],
0x2C: [.121, .194, .307],
0x2D: [.251, -0.18, .358],
0x2E: [.121, 0, .307],
0x2F: [.716, .215, .778],
0x30: [.665, .021, .511, {ic: .051}],
0x31: [.666, 0, .511],
0x32: [.666, .022, .511, {ic: .04}],
0x33: [.666, .022, .511, {ic: .051}],
0x34: [.666, .194, .511],
0x35: [.666, .022, .511, {ic: .056}],
0x36: [.665, .022, .511, {ic: .054}],
0x37: [.666, .022, .511, {ic: .123}],
0x38: [.666, .021, .511, {ic: .042}],
0x39: [.666, .022, .511, {ic: .042}],
0x3A: [.431, 0, .307],
0x3B: [.431, .194, .307],
0x3D: [.367, -0.133, .767],
0x3F: [.716, 0, .511, {ic: .04}],
0x40: [.705, .011, .767, {ic: .022}],
0x5B: [.75, .25, .307, {ic: .139}],
0x5D: [.75, .25, .307, {ic: .052}],
0x5E: [.694, -0.527, .511, {ic: .017}],
0x5F: [-0.025, .062, .511, {ic: .043}],
0x7E: [.318, -0.208, .511, {ic: .06}],
0x131: [.441, .01, .307, {ic: .033}],
0x237: [.442, .204, .332],
0x300: [.697, -0.5, 0],
0x301: [.697, -0.5, 0, {ic: .039}],
0x302: [.694, -0.527, 0, {ic: .017}],
0x303: [.668, -0.558, 0, {ic: .06}],
0x304: [.589, -0.544, 0, {ic: .054}],
0x306: [.694, -0.515, 0, {ic: .062}],
0x307: [.669, -0.548, 0],
0x308: [.669, -0.554, 0, {ic: .045}],
0x30A: [.716, -0.542, 0],
0x30B: [.697, -0.503, 0, {ic: .065}],
0x30C: [.638, -0.502, 0, {ic: .029}],
0x3DD: [.605, .085, .778],
0x2013: [.285, -0.248, .511, {ic: .043}],
0x2014: [.285, -0.248, 1.022, {ic: .016}],
0x2015: [.285, -0.248, 1.022, {ic: .016}],
0x2017: [-0.025, .062, .511, {ic: .043}],
0x2018: [.694, -0.379, .307, {ic: .055}],
0x2019: [.694, -0.379, .307, {ic: .07}],
0x201C: [.694, -0.379, .514, {ic: .092}],
0x201D: [.694, -0.379, .514, {ic: .024}],
0x2044: [.716, .215, .778],
0x210F: [.695, .013, .54, {ic: .022}],
0x2206: [.716, 0, .833, {sk: .167}],
0x29F8: [.716, .215, .778],
};
+71
View File
@@ -0,0 +1,71 @@
/*************************************************************
*
* Copyright (c) 2018-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import {CharMap, CharOptions} from '../../FontData.js';
export const largeop: CharMap<CharOptions> = {
0x28: [1.15, .649, .597],
0x29: [1.15, .649, .597],
0x2F: [1.15, .649, .811],
0x5B: [1.15, .649, .472],
0x5C: [1.15, .649, .811],
0x5D: [1.15, .649, .472],
0x7B: [1.15, .649, .667],
0x7D: [1.15, .649, .667],
0x2C6: [.772, -0.565, 1],
0x2DC: [.75, -0.611, 1],
0x302: [.772, -0.565, 0],
0x303: [.75, -0.611, 0],
0x2016: [.602, 0, .778],
0x2044: [1.15, .649, .811],
0x2191: [.6, 0, .667],
0x2193: [.6, 0, .667],
0x21D1: [.599, 0, .778],
0x21D3: [.6, 0, .778],
0x220F: [.95, .45, 1.278],
0x2210: [.95, .45, 1.278],
0x2211: [.95, .45, 1.444],
0x221A: [1.15, .65, 1, {ic: .02}],
0x2223: [.627, .015, .333],
0x2225: [.627, .015, .556],
0x222B: [1.36, .862, .556, {ic: .388}],
0x222C: [1.36, .862, 1.084, {ic: .388}],
0x222D: [1.36, .862, 1.592, {ic: .388}],
0x222E: [1.36, .862, .556, {ic: .388}],
0x22C0: [.95, .45, 1.111],
0x22C1: [.95, .45, 1.111],
0x22C2: [.949, .45, 1.111],
0x22C3: [.95, .449, 1.111],
0x2308: [1.15, .649, .528],
0x2309: [1.15, .649, .528],
0x230A: [1.15, .649, .528],
0x230B: [1.15, .649, .528],
0x2329: [1.15, .649, .611],
0x232A: [1.15, .649, .611],
0x23D0: [.602, 0, .667],
0x2758: [.627, .015, .333],
0x27E8: [1.15, .649, .611],
0x27E9: [1.15, .649, .611],
0x2A00: [.949, .449, 1.511],
0x2A01: [.949, .449, 1.511],
0x2A02: [.949, .449, 1.511],
0x2A04: [.95, .449, 1.111],
0x2A06: [.95, .45, 1.111],
0x2A0C: [1.36, .862, 2.168, {ic: .388}],
0x3008: [1.15, .649, .611],
0x3009: [1.15, .649, .611],
};
+99
View File
@@ -0,0 +1,99 @@
/*************************************************************
*
* Copyright (c) 2018-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import {CharMap, CharOptions} from '../../FontData.js';
export const monospace: CharMap<CharOptions> = {
0x20: [0, 0, .525],
0x21: [.622, 0, .525],
0x22: [.623, -0.333, .525],
0x23: [.611, 0, .525],
0x24: [.694, .082, .525],
0x25: [.694, .083, .525],
0x26: [.622, .011, .525],
0x27: [.611, -0.287, .525],
0x28: [.694, .082, .525],
0x29: [.694, .082, .525],
0x2A: [.52, -0.09, .525],
0x2B: [.531, -0.081, .525],
0x2C: [.14, .139, .525],
0x2D: [.341, -0.271, .525],
0x2E: [.14, 0, .525],
0x2F: [.694, .083, .525],
0x3A: [.431, 0, .525],
0x3B: [.431, .139, .525],
0x3C: [.557, -0.055, .525],
0x3D: [.417, -0.195, .525],
0x3E: [.557, -0.055, .525],
0x3F: [.617, 0, .525],
0x40: [.617, .006, .525],
0x5B: [.694, .082, .525],
0x5C: [.694, .083, .525],
0x5D: [.694, .082, .525],
0x5E: [.611, -0.46, .525],
0x5F: [-0.025, .095, .525],
0x60: [.681, -0.357, .525],
0x7B: [.694, .083, .525],
0x7C: [.694, .082, .525],
0x7D: [.694, .083, .525],
0x7E: [.611, -0.466, .525],
0x7F: [.612, -0.519, .525],
0xA0: [0, 0, .525],
0x131: [.431, 0, .525],
0x237: [.431, .228, .525],
0x2B9: [.623, -0.334, .525],
0x300: [.611, -0.485, 0],
0x301: [.611, -0.485, 0],
0x302: [.611, -0.46, 0],
0x303: [.611, -0.466, 0],
0x304: [.577, -0.5, 0],
0x306: [.611, -0.504, 0],
0x308: [.612, -0.519, 0],
0x30A: [.619, -0.499, 0],
0x30C: [.577, -0.449, 0],
0x391: [.623, 0, .525],
0x392: [.611, 0, .525],
0x393: [.611, 0, .525],
0x394: [.623, 0, .525],
0x395: [.611, 0, .525],
0x396: [.611, 0, .525],
0x397: [.611, 0, .525],
0x398: [.621, .01, .525],
0x399: [.611, 0, .525],
0x39A: [.611, 0, .525],
0x39B: [.623, 0, .525],
0x39C: [.611, 0, .525],
0x39D: [.611, 0, .525],
0x39E: [.611, 0, .525],
0x39F: [.621, .01, .525],
0x3A0: [.611, 0, .525],
0x3A1: [.611, 0, .525],
0x3A3: [.611, 0, .525],
0x3A4: [.611, 0, .525],
0x3A5: [.622, 0, .525],
0x3A6: [.611, 0, .525],
0x3A7: [.611, 0, .525],
0x3A8: [.611, 0, .525],
0x3A9: [.622, 0, .525],
0x2017: [-0.025, .095, .525],
0x2032: [.623, -0.334, .525],
0x2033: [.623, 0, 1.05],
0x2034: [.623, 0, 1.575],
0x2044: [.694, .083, .525],
0x2057: [.623, 0, 2.1],
0x2206: [.623, 0, .525],
};
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,23 @@
/*************************************************************
*
* Copyright (c) 2018-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import {CharMap, CharOptions} from '../../FontData.js';
export const sansSerifBoldItalic: CharMap<CharOptions> = {
0x131: [.458, 0, .256],
0x237: [.458, .205, .286],
};
@@ -0,0 +1,69 @@
/*************************************************************
*
* Copyright (c) 2018-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import {CharMap, CharOptions} from '../../FontData.js';
export const sansSerifBold: CharMap<CharOptions> = {
0x21: [.694, 0, .367],
0x22: [.694, -0.442, .558],
0x23: [.694, .193, .917],
0x24: [.75, .056, .55],
0x25: [.75, .056, 1.029],
0x26: [.716, .022, .831],
0x27: [.694, -0.442, .306],
0x28: [.75, .249, .428],
0x29: [.75, .25, .428],
0x2A: [.75, -0.293, .55],
0x2B: [.617, .116, .856],
0x2C: [.146, .106, .306],
0x2D: [.273, -0.186, .367],
0x2E: [.146, 0, .306],
0x2F: [.75, .249, .55],
0x3A: [.458, 0, .306],
0x3B: [.458, .106, .306],
0x3D: [.407, -0.094, .856],
0x3F: [.705, 0, .519],
0x40: [.704, .011, .733],
0x5B: [.75, .25, .343],
0x5D: [.75, .25, .343],
0x5E: [.694, -0.537, .55],
0x5F: [-0.023, .11, .55],
0x7E: [.344, -0.198, .55],
0x131: [.458, 0, .256],
0x237: [.458, .205, .286],
0x300: [.694, -0.537, 0],
0x301: [.694, -0.537, 0],
0x302: [.694, -0.537, 0],
0x303: [.694, -0.548, 0],
0x304: [.66, -0.56, 0],
0x306: [.694, -0.552, 0],
0x307: [.695, -0.596, 0],
0x308: [.695, -0.595, 0],
0x30A: [.694, -0.538, 0],
0x30B: [.694, -0.537, 0],
0x30C: [.657, -0.5, 0],
0x2013: [.327, -0.24, .55],
0x2014: [.327, -0.24, 1.1],
0x2015: [.327, -0.24, 1.1],
0x2017: [-0.023, .11, .55],
0x2018: [.694, -0.443, .306],
0x2019: [.694, -0.442, .306],
0x201C: [.694, -0.443, .558],
0x201D: [.694, -0.442, .558],
0x2044: [.75, .249, .55],
0x2206: [.694, 0, .917],
};
@@ -0,0 +1,103 @@
/*************************************************************
*
* Copyright (c) 2018-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import {CharMap, CharOptions} from '../../FontData.js';
export const sansSerifItalic: CharMap<CharOptions> = {
0x21: [.694, 0, .319, {ic: .036}],
0x22: [.694, -0.471, .5],
0x23: [.694, .194, .833, {ic: .018}],
0x24: [.75, .056, .5, {ic: .065}],
0x25: [.75, .056, .833],
0x26: [.716, .022, .758],
0x27: [.694, -0.471, .278, {ic: .057}],
0x28: [.75, .25, .389, {ic: .102}],
0x29: [.75, .25, .389],
0x2A: [.75, -0.306, .5, {ic: .068}],
0x2B: [.583, .083, .778],
0x2C: [.098, .125, .278],
0x2D: [.259, -0.186, .333],
0x2E: [.098, 0, .278],
0x2F: [.75, .25, .5, {ic: .1}],
0x30: [.678, .022, .5, {ic: .049}],
0x31: [.678, 0, .5],
0x32: [.678, 0, .5, {ic: .051}],
0x33: [.678, .022, .5, {ic: .044}],
0x34: [.656, 0, .5, {ic: .021}],
0x35: [.656, .022, .5, {ic: .055}],
0x36: [.678, .022, .5, {ic: .048}],
0x37: [.656, .011, .5, {ic: .096}],
0x38: [.678, .022, .5, {ic: .054}],
0x39: [.677, .022, .5, {ic: .045}],
0x3A: [.444, 0, .278],
0x3B: [.444, .125, .278],
0x3D: [.37, -0.13, .778, {ic: .018}],
0x3F: [.704, 0, .472, {ic: .064}],
0x40: [.705, .01, .667, {ic: .04}],
0x5B: [.75, .25, .289, {ic: .136}],
0x5D: [.75, .25, .289, {ic: .064}],
0x5E: [.694, -0.527, .5, {ic: .033}],
0x5F: [-0.038, .114, .5, {ic: .065}],
0x7E: [.327, -0.193, .5, {ic: .06}],
0x131: [.444, 0, .239, {ic: .019}],
0x237: [.444, .204, .267, {ic: .019}],
0x300: [.694, -0.527, 0],
0x301: [.694, -0.527, 0, {ic: .063}],
0x302: [.694, -0.527, 0, {ic: .033}],
0x303: [.677, -0.543, 0, {ic: .06}],
0x304: [.631, -0.552, 0, {ic: .064}],
0x306: [.694, -0.508, 0, {ic: .073}],
0x307: [.68, -0.576, 0],
0x308: [.68, -0.582, 0, {ic: .04}],
0x30A: [.693, -0.527, 0],
0x30B: [.694, -0.527, 0, {ic: .063}],
0x30C: [.654, -0.487, 0, {ic: .06}],
0x391: [.694, 0, .667],
0x392: [.694, 0, .667, {ic: .029}],
0x393: [.691, 0, .542, {ic: .104}],
0x394: [.694, 0, .833],
0x395: [.691, 0, .597, {ic: .091}],
0x396: [.694, 0, .611, {ic: .091}],
0x397: [.694, 0, .708, {ic: .06}],
0x398: [.715, .022, .778, {ic: .026}],
0x399: [.694, 0, .278, {ic: .06}],
0x39A: [.694, 0, .694, {ic: .091}],
0x39B: [.694, 0, .611],
0x39C: [.694, 0, .875, {ic: .054}],
0x39D: [.694, 0, .708, {ic: .058}],
0x39E: [.688, 0, .667, {ic: .098}],
0x39F: [.716, .022, .736, {ic: .027}],
0x3A0: [.691, 0, .708, {ic: .06}],
0x3A1: [.694, 0, .639, {ic: .051}],
0x3A3: [.694, 0, .722, {ic: .091}],
0x3A4: [.688, 0, .681, {ic: .109}],
0x3A5: [.716, 0, .778, {ic: .065}],
0x3A6: [.694, 0, .722, {ic: .021}],
0x3A7: [.694, 0, .667, {ic: .091}],
0x3A8: [.694, 0, .778, {ic: .076}],
0x3A9: [.716, 0, .722, {ic: .047}],
0x2013: [.312, -0.236, .5, {ic: .065}],
0x2014: [.312, -0.236, 1, {ic: .065}],
0x2015: [.312, -0.236, 1, {ic: .065}],
0x2017: [-0.038, .114, .5, {ic: .065}],
0x2018: [.694, -0.471, .278, {ic: .058}],
0x2019: [.694, -0.471, .278, {ic: .057}],
0x201C: [.694, -0.471, .5, {ic: .114}],
0x201D: [.694, -0.471, .5],
0x2044: [.75, .25, .5, {ic: .1}],
0x2206: [.694, 0, .833],
};
+93
View File
@@ -0,0 +1,93 @@
/*************************************************************
*
* Copyright (c) 2018-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import {CharMap, CharOptions} from '../../FontData.js';
export const sansSerif: CharMap<CharOptions> = {
0x21: [.694, 0, .319],
0x22: [.694, -0.471, .5],
0x23: [.694, .194, .833],
0x24: [.75, .056, .5],
0x25: [.75, .056, .833],
0x26: [.716, .022, .758],
0x27: [.694, -0.471, .278],
0x28: [.75, .25, .389],
0x29: [.75, .25, .389],
0x2A: [.75, -0.306, .5],
0x2B: [.583, .082, .778],
0x2C: [.098, .125, .278],
0x2D: [.259, -0.186, .333],
0x2E: [.098, 0, .278],
0x2F: [.75, .25, .5],
0x3A: [.444, 0, .278],
0x3B: [.444, .125, .278],
0x3D: [.37, -0.13, .778],
0x3F: [.704, 0, .472],
0x40: [.704, .011, .667],
0x5B: [.75, .25, .289],
0x5D: [.75, .25, .289],
0x5E: [.694, -0.527, .5],
0x5F: [-0.038, .114, .5],
0x7E: [.327, -0.193, .5],
0x131: [.444, 0, .239],
0x237: [.444, .205, .267],
0x300: [.694, -0.527, 0],
0x301: [.694, -0.527, 0],
0x302: [.694, -0.527, 0],
0x303: [.677, -0.543, 0],
0x304: [.631, -0.552, 0],
0x306: [.694, -0.508, 0],
0x307: [.68, -0.576, 0],
0x308: [.68, -0.582, 0],
0x30A: [.694, -0.527, 0],
0x30B: [.694, -0.527, 0],
0x30C: [.654, -0.487, 0],
0x391: [.694, 0, .667],
0x392: [.694, 0, .667],
0x393: [.691, 0, .542],
0x394: [.694, 0, .833],
0x395: [.691, 0, .597],
0x396: [.694, 0, .611],
0x397: [.694, 0, .708],
0x398: [.716, .021, .778],
0x399: [.694, 0, .278],
0x39A: [.694, 0, .694],
0x39B: [.694, 0, .611],
0x39C: [.694, 0, .875],
0x39D: [.694, 0, .708],
0x39E: [.688, 0, .667],
0x39F: [.715, .022, .736],
0x3A0: [.691, 0, .708],
0x3A1: [.694, 0, .639],
0x3A3: [.694, 0, .722],
0x3A4: [.688, 0, .681],
0x3A5: [.716, 0, .778],
0x3A6: [.694, 0, .722],
0x3A7: [.694, 0, .667],
0x3A8: [.694, 0, .778],
0x3A9: [.716, 0, .722],
0x2013: [.312, -0.236, .5],
0x2014: [.312, -0.236, 1],
0x2015: [.312, -0.236, 1],
0x2017: [-0.038, .114, .5],
0x2018: [.694, -0.471, .278],
0x2019: [.694, -0.471, .278],
0x201C: [.694, -0.471, .5],
0x201D: [.694, -0.471, .5],
0x2044: [.75, .25, .5],
0x2206: [.694, 0, .833],
};
+21
View File
@@ -0,0 +1,21 @@
/*************************************************************
*
* Copyright (c) 2018-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import {CharMap, CharOptions} from '../../FontData.js';
export const scriptBold: CharMap<CharOptions> = {
};
+21
View File
@@ -0,0 +1,21 @@
/*************************************************************
*
* Copyright (c) 2018-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import {CharMap, CharOptions} from '../../FontData.js';
export const script: CharMap<CharOptions> = {
};
+71
View File
@@ -0,0 +1,71 @@
/*************************************************************
*
* Copyright (c) 2018-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import {CharMap, CharOptions} from '../../FontData.js';
export const smallop: CharMap<CharOptions> = {
0x28: [.85, .349, .458],
0x29: [.85, .349, .458],
0x2F: [.85, .349, .578],
0x5B: [.85, .349, .417],
0x5C: [.85, .349, .578],
0x5D: [.85, .349, .417],
0x7B: [.85, .349, .583],
0x7D: [.85, .349, .583],
0x2C6: [.744, -0.551, .556],
0x2DC: [.722, -0.597, .556],
0x302: [.744, -0.551, 0],
0x303: [.722, -0.597, 0],
0x2016: [.602, 0, .778],
0x2044: [.85, .349, .578],
0x2191: [.6, 0, .667],
0x2193: [.6, 0, .667],
0x21D1: [.599, 0, .778],
0x21D3: [.6, 0, .778],
0x220F: [.75, .25, .944],
0x2210: [.75, .25, .944],
0x2211: [.75, .25, 1.056],
0x221A: [.85, .35, 1, {ic: .02}],
0x2223: [.627, .015, .333],
0x2225: [.627, .015, .556],
0x222B: [.805, .306, .472, {ic: .138}],
0x222C: [.805, .306, .819, {ic: .138}],
0x222D: [.805, .306, 1.166, {ic: .138}],
0x222E: [.805, .306, .472, {ic: .138}],
0x22C0: [.75, .249, .833],
0x22C1: [.75, .249, .833],
0x22C2: [.75, .249, .833],
0x22C3: [.75, .249, .833],
0x2308: [.85, .349, .472],
0x2309: [.85, .349, .472],
0x230A: [.85, .349, .472],
0x230B: [.85, .349, .472],
0x2329: [.85, .35, .472],
0x232A: [.85, .35, .472],
0x23D0: [.602, 0, .667],
0x2758: [.627, .015, .333],
0x27E8: [.85, .35, .472],
0x27E9: [.85, .35, .472],
0x2A00: [.75, .25, 1.111],
0x2A01: [.75, .25, 1.111],
0x2A02: [.75, .25, 1.111],
0x2A04: [.75, .249, .833],
0x2A06: [.75, .249, .833],
0x2A0C: [.805, .306, 1.638, {ic: .138}],
0x3008: [.85, .35, .472],
0x3009: [.85, .35, .472],
};
@@ -0,0 +1,49 @@
/*************************************************************
*
* Copyright (c) 2018-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import {CharMap, CharOptions} from '../../FontData.js';
export const texCalligraphicBold: CharMap<CharOptions> = {
0x41: [.751, .049, .921, {ic: .068, sk: .224}],
0x42: [.705, .017, .748, {sk: .16}],
0x43: [.703, .02, .613, {sk: .16}],
0x44: [.686, 0, .892, {sk: .0958}],
0x45: [.703, .016, .607, {ic: .02, sk: .128}],
0x46: [.686, .03, .814, {ic: .116, sk: .128}],
0x47: [.703, .113, .682, {sk: .128}],
0x48: [.686, .048, .987, {sk: .128}],
0x49: [.686, 0, .642, {ic: .104, sk: .0319}],
0x4A: [.686, .114, .779, {ic: .158, sk: .192}],
0x4B: [.703, .017, .871, {sk: .0639}],
0x4C: [.703, .017, .788, {sk: .16}],
0x4D: [.703, .049, 1.378, {sk: .16}],
0x4E: [.84, .049, .937, {ic: .168, sk: .0958}],
0x4F: [.703, .017, .906, {sk: .128}],
0x50: [.686, .067, .81, {ic: .036, sk: .0958}],
0x51: [.703, .146, .939, {sk: .128}],
0x52: [.686, .017, .99, {sk: .0958}],
0x53: [.703, .016, .696, {ic: .025, sk: .16}],
0x54: [.72, .069, .644, {ic: .303, sk: .0319}],
0x55: [.686, .024, .715, {ic: .056, sk: .0958}],
0x56: [.686, .077, .737, {ic: .037, sk: .0319}],
0x57: [.686, .077, 1.169, {ic: .037, sk: .0958}],
0x58: [.686, 0, .817, {ic: .089, sk: .16}],
0x59: [.686, .164, .759, {ic: .038, sk: .0958}],
0x5A: [.686, 0, .818, {ic: .035, sk: .16}],
0x131: [.452, .008, .394, {sk: .0319}],
0x237: [.451, .201, .439, {sk: .0958}],
};
@@ -0,0 +1,47 @@
/*************************************************************
*
* Copyright (c) 2018-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import {CharMap, CharOptions} from '../../FontData.js';
export const texCalligraphic: CharMap<CharOptions> = {
0x41: [.728, .05, .798, {ic: .021, sk: .194}],
0x42: [.705, .022, .657, {sk: .139}],
0x43: [.705, .025, .527, {sk: .139}],
0x44: [.683, 0, .771, {sk: .0833}],
0x45: [.705, .022, .528, {ic: .036, sk: .111}],
0x46: [.683, .032, .719, {ic: .11, sk: .111}],
0x47: [.704, .119, .595, {sk: .111}],
0x48: [.683, .048, .845, {sk: .111}],
0x49: [.683, 0, .545, {ic: .097, sk: .0278}],
0x4A: [.683, .119, .678, {ic: .161, sk: .167}],
0x4B: [.705, .022, .762, {sk: .0556}],
0x4C: [.705, .022, .69, {sk: .139}],
0x4D: [.705, .05, 1.201, {sk: .139}],
0x4E: [.789, .05, .82, {ic: .159, sk: .0833}],
0x4F: [.705, .022, .796, {sk: .111}],
0x50: [.683, .057, .696, {ic: .037, sk: .0833}],
0x51: [.705, .131, .817, {sk: .111}],
0x52: [.682, .022, .848, {sk: .0833}],
0x53: [.705, .022, .606, {ic: .036, sk: .139}],
0x54: [.717, .068, .545, {ic: .288, sk: .0278}],
0x55: [.683, .028, .626, {ic: .061, sk: .0833}],
0x56: [.683, .052, .613, {ic: .045, sk: .0278}],
0x57: [.683, .053, .988, {ic: .046, sk: .0833}],
0x58: [.683, 0, .713, {ic: .094, sk: .139}],
0x59: [.683, .143, .668, {ic: .046, sk: .0833}],
0x5A: [.683, 0, .725, {ic: .042, sk: .139}],
};
+73
View File
@@ -0,0 +1,73 @@
/*************************************************************
*
* Copyright (c) 2018-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import {CharMap, CharOptions} from '../../FontData.js';
export const texMathit: CharMap<CharOptions> = {
0x41: [.716, 0, .743],
0x42: [.683, 0, .704],
0x43: [.705, .021, .716],
0x44: [.683, 0, .755],
0x45: [.68, 0, .678],
0x46: [.68, 0, .653],
0x47: [.705, .022, .774],
0x48: [.683, 0, .743],
0x49: [.683, 0, .386],
0x4A: [.683, .021, .525],
0x4B: [.683, 0, .769],
0x4C: [.683, 0, .627],
0x4D: [.683, 0, .897],
0x4E: [.683, 0, .743],
0x4F: [.704, .022, .767],
0x50: [.683, 0, .678],
0x51: [.704, .194, .767],
0x52: [.683, .022, .729],
0x53: [.705, .022, .562],
0x54: [.677, 0, .716],
0x55: [.683, .022, .743],
0x56: [.683, .022, .743],
0x57: [.683, .022, .999],
0x58: [.683, 0, .743],
0x59: [.683, 0, .743],
0x5A: [.683, 0, .613],
0x61: [.442, .011, .511],
0x62: [.694, .011, .46],
0x63: [.441, .01, .46],
0x64: [.694, .011, .511],
0x65: [.442, .01, .46],
0x66: [.705, .204, .307],
0x67: [.442, .205, .46],
0x68: [.694, .011, .511],
0x69: [.656, .01, .307],
0x6A: [.656, .204, .307],
0x6B: [.694, .011, .46],
0x6C: [.694, .011, .256],
0x6D: [.442, .011, .818],
0x6E: [.442, .011, .562],
0x6F: [.442, .011, .511],
0x70: [.442, .194, .511],
0x71: [.442, .194, .46],
0x72: [.442, .011, .422],
0x73: [.442, .011, .409],
0x74: [.626, .011, .332],
0x75: [.441, .011, .537],
0x76: [.443, .01, .46],
0x77: [.443, .011, .664],
0x78: [.442, .011, .464],
0x79: [.441, .205, .486],
0x7A: [.442, .011, .409],
};
@@ -0,0 +1,57 @@
/*************************************************************
*
* Copyright (c) 2018-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import {CharMap, CharOptions} from '../../FontData.js';
export const texOldstyleBold: CharMap<CharOptions> = {
0x30: [.46, .017, .575],
0x31: [.461, 0, .575],
0x32: [.46, 0, .575],
0x33: [.461, .211, .575],
0x34: [.469, .194, .575],
0x35: [.461, .211, .575],
0x36: [.66, .017, .575],
0x37: [.476, .211, .575],
0x38: [.661, .017, .575],
0x39: [.461, .21, .575],
0x41: [.751, .049, .921, {ic: .068, sk: .224}],
0x42: [.705, .017, .748, {sk: .16}],
0x43: [.703, .02, .613, {sk: .16}],
0x44: [.686, 0, .892, {sk: .0958}],
0x45: [.703, .016, .607, {ic: .02, sk: .128}],
0x46: [.686, .03, .814, {ic: .116, sk: .128}],
0x47: [.703, .113, .682, {sk: .128}],
0x48: [.686, .048, .987, {sk: .128}],
0x49: [.686, 0, .642, {ic: .104, sk: .0319}],
0x4A: [.686, .114, .779, {ic: .158, sk: .192}],
0x4B: [.703, .017, .871, {sk: .0639}],
0x4C: [.703, .017, .788, {sk: .16}],
0x4D: [.703, .049, 1.378, {sk: .16}],
0x4E: [.84, .049, .937, {ic: .168, sk: .0958}],
0x4F: [.703, .017, .906, {sk: .128}],
0x50: [.686, .067, .81, {ic: .036, sk: .0958}],
0x51: [.703, .146, .939, {sk: .128}],
0x52: [.686, .017, .99, {sk: .0958}],
0x53: [.703, .016, .696, {ic: .025, sk: .16}],
0x54: [.72, .069, .644, {ic: .303, sk: .0319}],
0x55: [.686, .024, .715, {ic: .056, sk: .0958}],
0x56: [.686, .077, .737, {ic: .037, sk: .0319}],
0x57: [.686, .077, 1.169, {ic: .037, sk: .0958}],
0x58: [.686, 0, .817, {ic: .089, sk: .16}],
0x59: [.686, .164, .759, {ic: .038, sk: .0958}],
0x5A: [.686, 0, .818, {ic: .035, sk: .16}],
};
+57
View File
@@ -0,0 +1,57 @@
/*************************************************************
*
* Copyright (c) 2018-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import {CharMap, CharOptions} from '../../FontData.js';
export const texOldstyle: CharMap<CharOptions> = {
0x30: [.452, .022, .5],
0x31: [.453, 0, .5],
0x32: [.453, 0, .5],
0x33: [.452, .216, .5],
0x34: [.464, .194, .5],
0x35: [.453, .216, .5],
0x36: [.665, .022, .5],
0x37: [.463, .216, .5],
0x38: [.666, .021, .5],
0x39: [.453, .216, .5],
0x41: [.728, .05, .798, {ic: .021, sk: .194}],
0x42: [.705, .022, .657, {sk: .139}],
0x43: [.705, .025, .527, {sk: .139}],
0x44: [.683, 0, .771, {sk: .0833}],
0x45: [.705, .022, .528, {ic: .036, sk: .111}],
0x46: [.683, .032, .719, {ic: .11, sk: .111}],
0x47: [.704, .119, .595, {sk: .111}],
0x48: [.683, .048, .845, {sk: .111}],
0x49: [.683, 0, .545, {ic: .097, sk: .0278}],
0x4A: [.683, .119, .678, {ic: .161, sk: .167}],
0x4B: [.705, .022, .762, {sk: .0556}],
0x4C: [.705, .022, .69, {sk: .139}],
0x4D: [.705, .05, 1.201, {sk: .139}],
0x4E: [.789, .05, .82, {ic: .159, sk: .0833}],
0x4F: [.705, .022, .796, {sk: .111}],
0x50: [.683, .057, .696, {ic: .037, sk: .0833}],
0x51: [.705, .131, .817, {sk: .111}],
0x52: [.682, .022, .848, {sk: .0833}],
0x53: [.705, .022, .606, {ic: .036, sk: .139}],
0x54: [.717, .068, .545, {ic: .288, sk: .0278}],
0x55: [.683, .028, .626, {ic: .061, sk: .0833}],
0x56: [.683, .052, .613, {ic: .045, sk: .0278}],
0x57: [.683, .053, .988, {ic: .046, sk: .0833}],
0x58: [.683, 0, .713, {ic: .094, sk: .139}],
0x59: [.683, .143, .668, {ic: .046, sk: .0833}],
0x5A: [.683, 0, .725, {ic: .042, sk: .139}],
};
+45
View File
@@ -0,0 +1,45 @@
/*************************************************************
*
* Copyright (c) 2018-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import {CharMap, CharOptions} from '../../FontData.js';
export const texSize3: CharMap<CharOptions> = {
0x28: [1.45, .949, .736],
0x29: [1.45, .949, .736],
0x2F: [1.45, .949, 1.044],
0x5B: [1.45, .949, .528],
0x5C: [1.45, .949, 1.044],
0x5D: [1.45, .949, .528],
0x7B: [1.45, .949, .75],
0x7D: [1.45, .949, .75],
0x2C6: [.772, -0.564, 1.444],
0x2DC: [.749, -0.61, 1.444],
0x302: [.772, -0.564, 0],
0x303: [.749, -0.61, 0],
0x2044: [1.45, .949, 1.044],
0x221A: [1.45, .95, 1, {ic: .02}],
0x2308: [1.45, .949, .583],
0x2309: [1.45, .949, .583],
0x230A: [1.45, .949, .583],
0x230B: [1.45, .949, .583],
0x2329: [1.45, .95, .75],
0x232A: [1.45, .949, .75],
0x27E8: [1.45, .95, .75],
0x27E9: [1.45, .949, .75],
0x3008: [1.45, .95, .75],
0x3009: [1.45, .949, .75],
};
+74
View File
@@ -0,0 +1,74 @@
/*************************************************************
*
* Copyright (c) 2018-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import {CharMap, CharOptions} from '../../FontData.js';
export const texSize4: CharMap<CharOptions> = {
0x28: [1.75, 1.249, .792],
0x29: [1.75, 1.249, .792],
0x2F: [1.75, 1.249, 1.278],
0x5B: [1.75, 1.249, .583],
0x5C: [1.75, 1.249, 1.278],
0x5D: [1.75, 1.249, .583],
0x7B: [1.75, 1.249, .806],
0x7D: [1.75, 1.249, .806],
0x2C6: [.845, -0.561, 1.889, {ic: .013}],
0x2DC: [.823, -0.583, 1.889],
0x302: [.845, -0.561, 0, {ic: .013}],
0x303: [.823, -0.583, 0],
0x2044: [1.75, 1.249, 1.278],
0x221A: [1.75, 1.25, 1, {ic: .02}],
0x2308: [1.75, 1.249, .639],
0x2309: [1.75, 1.249, .639],
0x230A: [1.75, 1.249, .639],
0x230B: [1.75, 1.249, .639],
0x2329: [1.75, 1.248, .806],
0x232A: [1.75, 1.248, .806],
0x239B: [1.154, .655, .875],
0x239C: [.61, .01, .875],
0x239D: [1.165, .644, .875],
0x239E: [1.154, .655, .875],
0x239F: [.61, .01, .875],
0x23A0: [1.165, .644, .875],
0x23A1: [1.154, .645, .667],
0x23A2: [.602, 0, .667],
0x23A3: [1.155, .644, .667],
0x23A4: [1.154, .645, .667],
0x23A5: [.602, 0, .667],
0x23A6: [1.155, .644, .667],
0x23A7: [.899, .01, .889],
0x23A8: [1.16, .66, .889],
0x23A9: [.01, .899, .889],
0x23AA: [.29, .015, .889],
0x23AB: [.899, .01, .889],
0x23AC: [1.16, .66, .889],
0x23AD: [.01, .899, .889],
0x23B7: [.935, .885, 1.056],
0x27E8: [1.75, 1.248, .806],
0x27E9: [1.75, 1.248, .806],
0x3008: [1.75, 1.248, .806],
0x3009: [1.75, 1.248, .806],
0xE000: [.625, .014, 1.056],
0xE001: [.605, .014, 1.056, {ic: .02}],
0xE150: [.12, .213, .45, {ic: .01}],
0xE151: [.12, .213, .45, {ic: .024}],
0xE152: [.333, 0, .45, {ic: .01}],
0xE153: [.333, 0, .45, {ic: .024}],
0xE154: [.32, .2, .4, {ic: .01}],
0xE155: [.333, 0, .9, {ic: .01}],
0xE156: [.12, .213, .9, {ic: .01}],
};
+59
View File
@@ -0,0 +1,59 @@
/*************************************************************
*
* Copyright (c) 2018-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import {CharMap, CharOptions} from '../../FontData.js';
export const texVariant: CharMap<CharOptions> = {
0x2C6: [.845, -0.561, 2.333, {ic: .013}],
0x2DC: [.899, -0.628, 2.333],
0x302: [.845, -0.561, 0, {ic: .013}],
0x303: [.899, -0.628, 0],
0x3F0: [.434, .006, .667, {ic: .067}],
0x210F: [.695, .013, .54, {ic: .022}],
0x2190: [.437, -0.064, .5],
0x2192: [.437, -0.064, .5],
0x21CC: [.514, .014, 1],
0x2204: [.86, .166, .556],
0x2205: [.587, 0, .778],
0x2212: [.27, -0.23, .5],
0x2216: [.43, .023, .778],
0x221D: [.472, -0.028, .778],
0x2223: [.43, .023, .222],
0x2224: [.43, .023, .222, {ic: .018}],
0x2225: [.431, .023, .389],
0x2226: [.431, .024, .389, {ic: .018}],
0x223C: [.365, -0.132, .778],
0x2248: [.481, -0.05, .778],
0x2268: [.752, .284, .778],
0x2269: [.752, .284, .778],
0x2270: [.919, .421, .778],
0x2271: [.919, .421, .778],
0x2288: [.828, .33, .778],
0x2289: [.828, .33, .778],
0x228A: [.634, .255, .778],
0x228B: [.634, .254, .778],
0x22A8: [.694, 0, .611],
0x22C5: [.189, 0, .278],
0x2322: [.378, -0.122, .778],
0x2323: [.378, -0.143, .778],
0x25B3: [.575, .02, .722],
0x25BD: [.576, .019, .722],
0x2A87: [.801, .303, .778],
0x2A88: [.801, .303, .778],
0x2ACB: [.752, .332, .778],
0x2ACC: [.752, .333, .778],
};