/** * \file math_factory.C * This file is part of LyX, the document processor. * Licence details can be found in the file COPYING. * * \author André Pönitz * * Full author contact details are available in file CREDITS. */ #include #include "math_factory.h" #include "math_parser.h" #include "math_arrayinset.h" #include "math_amsarrayinset.h" #include "math_binominset.h" #include "math_boxinset.h" #include "math_boxedinset.h" #include "math_boldsymbolinset.h" #include "math_casesinset.h" #include "math_colorinset.h" #include "math_decorationinset.h" #include "math_dfracinset.h" #include "math_dotsinset.h" #include "math_fboxinset.h" #include "math_frameboxinset.h" #include "math_fontinset.h" #include "math_fontoldinset.h" #include "math_fracinset.h" #include "math_kerninset.h" #include "math_lefteqninset.h" #include "math_macro.h" #include "math_macroarg.h" #include "math_macrotable.h" #include "math_macrotemplate.h" #include "math_makeboxinset.h" #include "math_oversetinset.h" #include "math_parser.h" #include "math_rootinset.h" #include "math_sizeinset.h" #include "math_spaceinset.h" #include "math_splitinset.h" #include "math_sqrtinset.h" #include "math_stackrelinset.h" #include "math_substackinset.h" #include "math_symbolinset.h" #include "math_tabularinset.h" #include "math_tfracinset.h" #include "math_undersetinset.h" #include "math_unknowninset.h" #include "math_xarrowinset.h" #include "math_xymatrixinset.h" //#include "insets/insetref.h" #include "ref_inset.h" #include "debug.h" #include "math_support.h" #include "support/filetools.h" // LibFileSearch #include "support/lstrings.h" #include "frontends/lyx_gui.h" #include #include using lyx::support::LibFileSearch; using lyx::support::split; using std::string; using std::endl; using std::istringstream; bool has_math_fonts; namespace { // file scope typedef std::map WordList; WordList theWordList; bool math_font_available(string & name) { LyXFont f; augmentFont(f, name); // Do we have the font proper? if (lyx_gui::font_available(f)) return true; // can we fake it? if (name == "eufrak") { name = "lyxfakefrak"; return true; } lyxerr[Debug::MATHED] << "font " << name << " not available and I can't fake it" << endl; return false; } void initSymbols() { string const filename = LibFileSearch(string(), "symbols"); lyxerr[Debug::MATHED] << "read symbols from " << filename << endl; if (filename.empty()) { lyxerr << "Could not find symbols file" << endl; return; } std::ifstream fs(filename.c_str()); string line; bool skip = false; while (getline(fs, line)) { int charid = 0; int fallbackid = 0; if (!line.empty() && line[0] == '#') continue; // special case of iffont/else/endif if (line.size() >= 7 && line.substr(0, 6) == "iffont") { istringstream is(line); string tmp; is >> tmp; is >> tmp; skip = !math_font_available(tmp); continue; } else if (line.size() >= 4 && line.substr(0, 4) == "else") { skip = !skip; } else if (line.size() >= 5 && line.substr(0, 5) == "endif") { skip = false; continue; } else if (skip) continue; // special case of pre-defined macros if (line.size() > 8 && line.substr(0, 5) == "\\def\\") { //lyxerr << "macro definition: '" << line << '\'' << endl; MacroTable::globalMacros().insert(line); continue; } istringstream is(line); latexkeys tmp; is >> tmp.name >> tmp.inset; if (isFontName(tmp.inset)) is >> charid >> fallbackid >> tmp.extra >> tmp.xmlname; else is >> tmp.extra; if (!is) { lyxerr[Debug::MATHED] << "skipping line '" << line << '\'' << endl; lyxerr[Debug::MATHED] << tmp.name << ' ' << tmp.inset << ' ' << tmp.extra << endl; continue; } if (isFontName(tmp.inset)) { // tmp.inset _is_ the fontname here. // create fallbacks if necessary // store requirements as long as we can if (tmp.inset == "msa" || tmp.inset == "msb") tmp.requires = "amssymb"; // See http://bugzilla.lyx.org/show_bug.cgi?id=1942 // else if (tmp.inset == "wasy") // tmp.requires = "wasysym"; // symbol font is not available sometimes string symbol_font = "lyxsymbol"; if (tmp.extra == "func" || tmp.extra == "funclim" || tmp.extra == "special") { lyxerr[Debug::MATHED] << "symbol abuse for " << tmp.name << endl; tmp.draw = tmp.name; } else if (math_font_available(tmp.inset)) { lyxerr[Debug::MATHED] << "symbol available for " << tmp.name << endl; tmp.draw += char(charid); } else if (fallbackid && math_font_available(symbol_font)) { if (tmp.inset == "cmex") tmp.inset = "lyxsymbol"; else tmp.inset = "lyxboldsymbol"; lyxerr[Debug::MATHED] << "symbol fallback for " << tmp.name << endl; tmp.draw += char(fallbackid); } else { lyxerr[Debug::MATHED] << "faking " << tmp.name << endl; tmp.draw = tmp.name; tmp.inset = "lyxtex"; } } else { // it's a proper inset lyxerr[Debug::MATHED] << "inset " << tmp.inset << " used for " << tmp.name << endl; } if (theWordList.find(tmp.name) != theWordList.end()) lyxerr[Debug::MATHED] << "readSymbols: inset " << tmp.name << " already exists." << endl; else theWordList[tmp.name] = tmp; lyxerr[Debug::MATHED] << "read symbol '" << tmp.name << " inset: " << tmp.inset << " draw: " << int(tmp.draw.empty() ? 0 : tmp.draw[0]) << " extra: " << tmp.extra << '\'' << endl; } string tmp = "cmm"; string tmp2 = "cmsy"; has_math_fonts = math_font_available(tmp) && math_font_available(tmp2); } } // namespace anon void initMath() { static bool initialized = false; if (!initialized) { initialized = true; initParser(); initSymbols(); } } latexkeys const * in_word_set(string const & str) { WordList::iterator it = theWordList.find(str); return it != theWordList.end() ? &(it->second) : 0; } MathAtom createMathInset(string const & s) { //lyxerr << "creating inset with name: '" << s << '\'' << endl; latexkeys const * l = in_word_set(s); if (l) { string const & inset = l->inset; //lyxerr << " found inset: '" << inset << '\'' << endl; if (inset == "ref") return MathAtom(new RefInset(l->name)); if (inset == "overset") return MathAtom(new MathOversetInset); if (inset == "underset") return MathAtom(new MathUndersetInset); if (inset == "decoration") return MathAtom(new MathDecorationInset(l)); if (inset == "space") return MathAtom(new MathSpaceInset(l->name)); if (inset == "dots") return MathAtom(new MathDotsInset(l)); if (inset == "mbox") // return MathAtom(new MathMBoxInset); // MathMBoxInset is proposed to replace MathBoxInset, // but is not ready yet (it needs a BufferView for // construction) return MathAtom(new MathBoxInset(l->name)); // if (inset == "fbox") // return MathAtom(new MathFboxInset(l)); if (inset == "style") return MathAtom(new MathSizeInset(l)); if (inset == "font") return MathAtom(new MathFontInset(l)); if (inset == "oldfont") return MathAtom(new MathFontOldInset(l)); if (inset == "matrix") return MathAtom(new MathAMSArrayInset(s)); return MathAtom(new MathSymbolInset(l)); } if (s.size() == 2 && s[0] == '#' && s[1] >= '1' && s[1] <= '9') return MathAtom(new MathMacroArgument(s[1] - '0')); if (s.size() == 3 && s[0] == '\\' && s[1] == '#' && s[2] >= '1' && s[2] <= '9') return MathAtom(new MathMacroArgument(s[2] - '0')); if (s == "boxed") return MathAtom(new MathBoxedInset()); if (s == "fbox") return MathAtom(new MathFboxInset()); if (s == "framebox") return MathAtom(new MathFrameboxInset); if (s == "makebox") return MathAtom(new MathMakeboxInset); if (s == "kern") return MathAtom(new MathKernInset); if (s == "xymatrix") return MathAtom(new MathXYMatrixInset); if (s == "xrightarrow" || s == "xleftarrow") return MathAtom(new MathXArrowInset(s)); if (s == "split" || s == "gathered" || s == "aligned" || s == "alignedat") return MathAtom(new MathSplitInset(s)); if (s == "cases") return MathAtom(new MathCasesInset); if (s == "substack") return MathAtom(new MathSubstackInset); if (s == "subarray" || s == "array") return MathAtom(new MathArrayInset(s, 1, 1)); if (s == "sqrt") return MathAtom(new MathSqrtInset); if (s == "root") return MathAtom(new MathRootInset); if (s == "tabular") return MathAtom(new MathTabularInset(s, 1, 1)); if (s == "stackrel") return MathAtom(new MathStackrelInset); if (s == "binom" || s == "choose") return MathAtom(new MathBinomInset(s == "choose")); if (s == "over" || s == "frac") return MathAtom(new MathFracInset); if (s == "nicefrac") return MathAtom(new MathFracInset(MathFracInset::NICEFRAC)); //if (s == "infer") // return MathAtom(new MathInferInset); if (s == "atop") return MathAtom(new MathFracInset(MathFracInset::ATOP)); if (s == "lefteqn") return MathAtom(new MathLefteqnInset); if (s == "boldsymbol") return MathAtom(new MathBoldsymbolInset); if (s == "color" || s == "normalcolor") return MathAtom(new MathColorInset(true)); if (s == "textcolor") return MathAtom(new MathColorInset(false)); if (s == "dfrac") return MathAtom(new MathDfracInset); if (s == "tfrac") return MathAtom(new MathTfracInset); if (MacroTable::globalMacros().has(s)) return MathAtom(new MathMacro(s, MacroTable::globalMacros().get(s).numargs())); //if (MacroTable::localMacros().has(s)) // return MathAtom(new MathMacro(s, // MacroTable::localMacros().get(s).numargs())); //lyxerr << "creating unknown inset '" << s << "'" << endl; return MathAtom(new MathUnknownInset(s)); } bool createMathInset_fromDialogStr(string const & str, MathArray & ar) { // An example str: // "ref LatexCommand \\ref{sec:Title}\n\\end_inset\n\n"; string name; string body = split(str, name, ' '); if (name != "ref" ) return false; // body comes with a head "LatexCommand " and a // tail "\nend_inset\n\n". Strip them off. string trimmed; body = split(body, trimmed, ' '); split(body, trimmed, '\n'); mathed_parse_cell(ar, trimmed); if (ar.size() != 1) return false; return ar[0].nucleus(); }