From d4aa6a7253327ff000a962e10a06505f6fde66dd Mon Sep 17 00:00:00 2001 From: Erik Demaine Date: Sun, 15 Jan 2017 19:05:21 -0500 Subject: [PATCH] Fix all AMS mathord symbols (#618) * Fix all AMS mathord symbols * Fix \imath, \jmath, \pounds support * Fix \mathit support * Fix Greek capitals * Default font to main (fix Unicode support) * Now using correct \maltese * Correct mathit documentation * var -> const * Add trailing commas * Remove greekCapitals (no longer needed) --- src/buildCommon.js | 101 ++++++++++-------- test/screenshotter/images/Symbols1-chrome.png | Bin 6420 -> 6470 bytes .../screenshotter/images/Symbols1-firefox.png | Bin 5519 -> 5569 bytes 3 files changed, 56 insertions(+), 45 deletions(-) diff --git a/src/buildCommon.js b/src/buildCommon.js index 47e02c90..47773425 100644 --- a/src/buildCommon.js +++ b/src/buildCommon.js @@ -9,27 +9,28 @@ const fontMetrics = require("./fontMetrics"); const symbols = require("./symbols"); const utils = require("./utils"); -const greekCapitals = [ - "\\Gamma", - "\\Delta", - "\\Theta", - "\\Lambda", - "\\Xi", - "\\Pi", - "\\Sigma", - "\\Upsilon", - "\\Phi", - "\\Psi", - "\\Omega", -]; - // The following have to be loaded from Main-Italic font, using class mainit const mainitLetters = [ - "\u0131", // dotless i, \imath - "\u0237", // dotless j, \jmath - "\u00a3", // \pounds + "\\imath", // dotless i + "\\jmath", // dotless j + "\\pounds", // pounds symbol ]; +/** + * Looks up the given symbol in fontMetrics, after applying any symbol + * replacements defined in symbol.js + */ +const lookupSymbol = function(value, fontFamily, mode) { + // Replace the value with its replaced value from symbol.js + if (symbols[mode][value] && symbols[mode][value].replace) { + value = symbols[mode][value].replace; + } + return { + value: value, + metrics: fontMetrics.getCharacterMetrics(value, fontFamily), + }; +}; + /** * Makes a symbolNode after translation via the list of symbols in symbols.js. * Correctly pulls out metrics for the character, and optionally takes a list of @@ -40,12 +41,9 @@ const mainitLetters = [ * should if present come first in `classes`. */ const makeSymbol = function(value, fontFamily, mode, options, classes) { - // Replace the value with its replaced value from symbol.js - if (symbols[mode][value] && symbols[mode][value].replace) { - value = symbols[mode][value].replace; - } - - const metrics = fontMetrics.getCharacterMetrics(value, fontFamily); + const lookup = lookupSymbol(value, fontFamily, mode); + const metrics = lookup.metrics; + value = lookup.value; let symbolNode; if (metrics) { @@ -100,29 +98,44 @@ const mathsym = function(value, mode, options, classes) { */ const mathDefault = function(value, mode, options, classes, type) { if (type === "mathord") { - return mathit(value, mode, options, classes); + const fontLookup = mathit(value, mode, options, classes); + return makeSymbol(value, fontLookup.fontName, mode, options, + classes.concat([fontLookup.fontClass])); } else if (type === "textord") { - return makeSymbol( - value, "Main-Regular", mode, options, classes.concat(["mathrm"])); + const font = symbols[mode][value] && symbols[mode][value].font; + if (font === "ams") { + return makeSymbol( + value, "AMS-Regular", mode, options, classes.concat(["amsrm"])); + } else { // if (font === "main") { + return makeSymbol( + value, "Main-Regular", mode, options, + classes.concat(["mathrm"])); + } } else { throw new Error("unexpected type: " + type + " in mathDefault"); } }; /** - * Makes a symbol in the italic math font. + * Determines which of the two font names (Main-Italic and Math-Italic) and + * corresponding style tags (mainit or mathit) to use for font "mathit", + * depending on the symbol. Use this function instead of fontMap for font + * "mathit". */ const mathit = function(value, mode, options, classes) { if (/[0-9]/.test(value.charAt(0)) || // glyphs for \imath and \jmath do not exist in Math-Italic so we // need to use Main-Italic instead - utils.contains(mainitLetters, value) || - utils.contains(greekCapitals, value)) { - return makeSymbol( - value, "Main-Italic", mode, options, classes.concat(["mainit"])); + utils.contains(mainitLetters, value)) { + return { + fontName: "Main-Italic", + fontClass: "mainit", + }; } else { - return makeSymbol( - value, "Math-Italic", mode, options, classes.concat(["mathit"])); + return { + fontName: "Math-Italic", + fontClass: "mathit", + }; } }; @@ -131,25 +144,23 @@ const mathit = function(value, mode, options, classes) { */ const makeOrd = function(group, options, type) { const mode = group.mode; - let value = group.value; - if (symbols[mode][value] && symbols[mode][value].replace) { - value = symbols[mode][value].replace; - } + const value = group.value; const classes = ["mord"]; const font = options.font; if (font) { + let fontLookup; if (font === "mathit" || utils.contains(mainitLetters, value)) { - return mathit(value, mode, options, classes); + fontLookup = mathit(value, mode, options, classes); } else { - const fontName = fontMap[font].fontName; - if (fontMetrics.getCharacterMetrics(value, fontName)) { - return makeSymbol( - value, fontName, mode, options, classes.concat([font])); - } else { - return mathDefault(value, mode, options, classes, type); - } + fontLookup = fontMap[font]; + } + if (lookupSymbol(value, fontLookup.fontName, mode).metrics) { + return makeSymbol(value, fontLookup.fontName, mode, options, + classes.concat([fontLookup.fontClass || font])); + } else { + return mathDefault(value, mode, options, classes, type); } } else { return mathDefault(value, mode, options, classes, type); diff --git a/test/screenshotter/images/Symbols1-chrome.png b/test/screenshotter/images/Symbols1-chrome.png index d2adc7c85e98836d60e8de2568e688177674bd34..49fd13f062ac568d42ccf95c31c37c5604452bd5 100644 GIT binary patch delta 4299 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 diff --git a/test/screenshotter/images/Symbols1-firefox.png b/test/screenshotter/images/Symbols1-firefox.png index c6865972b8957b64971bc427c9c045aea6d78a94..705e5e3a265abe8f433691c2e52850ca84a5ef03 100644 GIT binary patch delta 3389 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 II;Vst0M;#Gr2qf` delta 3341 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 IIVCg!01Ma(YXATM