]> git.lyx.org Git - lyx.git/blobdiff - src/mathed/MathSupport.cpp
Improve appearance of dots at higher zoom levels
[lyx.git] / src / mathed / MathSupport.cpp
index 5b08f70bd41abdbec3d1a51d0170915464bcdeb7..cc8927fe7afd304f061f3364d02ebb689f681690 100644 (file)
 
 #include "MathSupport.h"
 
-#include "InsetMath.h"
+#include "InsetMathFont.h"
+#include "InsetMathSymbol.h"
 #include "MathData.h"
+#include "MathFactory.h"
 #include "MathParser.h"
 #include "MathStream.h"
 
+#include "LaTeXFeatures.h"
+#include "MetricsInfo.h"
+
 #include "frontends/FontLoader.h"
 #include "frontends/FontMetrics.h"
 #include "frontends/Painter.h"
 
+#include "support/Changer.h"
 #include "support/debug.h"
 #include "support/docstream.h"
+#include "support/lassert.h"
+#include "support/Length.h"
 
 #include <map>
-#include <sstream>
+#include <algorithm>
 
 using namespace std;
 
@@ -74,6 +82,7 @@ namespace {
 /*
  * Internal struct of a drawing: code n x1 y1 ... xn yn, where code is:
  * 0 = end, 1 = line, 2 = polyline, 3 = square line, 4 = square polyline
+ * 5 = rounded thick line (i.e. dot for short line)
  */
 
 
@@ -112,6 +121,95 @@ double const brace[] = {
 };
 
 
+double const mapsto[] = {
+       2, 3,
+       0.75, 0.015, 0.95, 0.5, 0.75, 0.985,
+       1, 0.015, 0.475, 0.945, 0.475,
+       1, 0.015, 0.015, 0.015, 0.985,
+       0
+};
+
+
+double const lhook[] = {
+       2, 3,
+       0.25, 0.015, 0.05, 0.5, 0.25, 0.985,
+       1, 0.015, 0.475, 0.7, 0.475,
+       2, 5,
+       0.7, 0.015, 0.825, 0.15, 0.985, 0.25,
+       0.825, 0.35, 0.7, 0.475,
+       0
+};
+
+
+double const rhook[] = {
+       2, 3,
+       0.75, 0.015, 0.95, 0.5, 0.75, 0.985,
+       1, 0.3, 0.475, 0.985, 0.475,
+       2, 5,
+       0.3, 0.015, 0.175, 0.15, 0.05, 0.25,
+       0.175, 0.35, 0.3, 0.475,
+       0
+};
+
+
+double const LRArrow[] = {
+       2, 3,
+       0.25, 0.015, 0.05, 0.5, 0.25, 0.985,
+       2, 3,
+       0.75, 0.015, 0.95, 0.5, 0.75, 0.985,
+       1, 0.2, 0.8, 0.8, 0.8,
+       1, 0.2, 0.2, 0.8, 0.2,
+       0
+};
+
+
+double const LArrow[] = {
+       2, 3,
+       0.25, 0.015, 0.05, 0.5, 0.25, 0.985,
+       1, 0.2, 0.8, 0.985, 0.8,
+       1, 0.2, 0.2, 0.985, 0.2,
+       0
+};
+
+
+double const lharpoondown[] = {
+       2, 2,
+       0.015, 0.5, 0.25, 0.985,
+       1, 0.02, 0.475, 0.985, 0.475,
+       0
+};
+
+
+double const lharpoonup[] = {
+       2, 2,
+       0.25, 0.015, 0.015, 0.5,
+       1, 0.02, 0.525, 0.985, 0.525,
+       0
+};
+
+
+double const lrharpoons[] = {
+       2, 2,
+       0.25, 0.015, 0.015, 0.225,
+       1, 0.02, 0.23, 0.985, 0.23,
+       2, 2,
+       0.75, 0.985, 0.985, 0.775,
+       1, 0.02, 0.7, 0.980, 0.7,
+       0
+};
+
+
+double const rlharpoons[] = {
+       2, 2,
+       0.75, 0.015, 0.985, 0.225,
+       1, 0.02, 0.23, 0.985, 0.23,
+       2, 2,
+       0.25, 0.985, 0.015, 0.775,
+       1, 0.02, 0.7, 0.980, 0.7,
+       0
+};
+
+
 double const arrow[] = {
        4, 7,
        0.0150, 0.7500, 0.2000, 0.6000, 0.3500, 0.3500,
@@ -138,7 +236,7 @@ double const udarrow[] = {
        0.015, 0.25,  0.5, 0.05, 0.95, 0.25,
        2, 3,
        0.015, 0.75,  0.5, 0.95, 0.95, 0.75,
-       1, 0.5, 0.2,  0.5, 0.8,
+       1, 0.5, 0.1,  0.5, 0.9,
        0
 };
 
@@ -161,6 +259,15 @@ double const brack[] = {
 };
 
 
+double const dbrack[] = {
+       2, 4,
+       0.95, 0.05,  0.05, 0.05,  0.05, 0.95,  0.95, 0.95,
+       2, 2,
+       0.50, 0.05,  0.50, 0.95,
+       0
+};
+
+
 double const corner[] = {
        2, 3,
        0.95, 0.05,  0.05, 0.05,  0.05, 0.95,
@@ -187,17 +294,35 @@ double const hline[] = {
 };
 
 
+double const dot[] = {
+//     1, 0.5, 0.2, 0.5, 0.2,
+//     1, 0.4, 0.4, 0.6, 0.4,
+//     1, 0.5, 0.5, 0.5, 0.5,
+       5, 0.4, 0.6, 0.6, 0.6,
+       0
+};
+
+
 double const ddot[] = {
-       1, 0.2, 0.5,  0.3, 0.5,
-       1, 0.7, 0.5,  0.8, 0.5,
+       5, 0.1, 0.6, 0.3, 0.6,
+       5, 0.6, 0.6, 0.8, 0.6,
        0
 };
 
 
 double const dddot[] = {
-       1, 0.1, 0.5,  0.2, 0.5,
-       1, 0.45, 0.5, 0.55, 0.5,
-       1, 0.8, 0.5,  0.9, 0.5,
+       5, -0.2, 0.6, 0.0, 0.6,
+       5,  0.3, 0.6, 0.5, 0.6,
+       5,  0.8, 0.6, 1.0, 0.6,
+       0
+};
+
+
+double const ddddot[] = {
+       5, -0.4, 0.6, -0.2, 0.6,
+       5,  0.1, 0.6,  0.3, 0.6,
+       5,  0.6, 0.6,  0.8, 0.6,
+       5,  1.1, 0.6,  1.3, 0.6,
        0
 };
 
@@ -218,15 +343,11 @@ double const dline3[] = {
 };
 
 
-double const hlinesmall[] = {
-       1, 0.4, 0.5, 0.6, 0.5,
-       0
-};
-
-
 double const ring[] = {
-       2, 5,
-       0.5, 0.8,  0.8, 0.5,  0.5, 0.2,  0.2, 0.5,  0.5, 0.8,
+       2, 9,
+       0.5, 0.8,  0.7, 0.7,  0.8, 0.4,
+       0.7, 0.1,  0.5, 0.0,  0.3, 0.1,
+       0.2, 0.4,  0.3, 0.7,  0.5, 0.8,
        0
 };
 
@@ -245,8 +366,8 @@ double const  Vert[] = {
 
 
 double const tilde[] = {
-       2, 4,
-       0.00, 0.8,  0.25, 0.2,  0.75, 0.8,  1.00, 0.2,
+       2, 6,
+       0.0, 0.8,  0.15, 0.2,  0.35, 0.2,  0.65, 0.8,  0.85, 0.8,  1.0, 0.2,
        0
 };
 
@@ -264,21 +385,36 @@ struct named_deco_struct {
 
 named_deco_struct deco_table[] = {
        // Decorations
-       {"widehat",             angle,    3 },
-       {"widetilde",           tilde,    0 },
-       {"underbar",            hline,    0 },
-       {"underline",           hline,    0 },
-       {"overline",            hline,    0 },
-       {"underbrace",          brace,    1 },
-       {"overbrace",           brace,    3 },
-       {"overleftarrow",       arrow,    1 },
-       {"overrightarrow",      arrow,    3 },
-       {"overleftrightarrow",  udarrow,  1 },
-       {"xleftarrow",          arrow,    1 },
-       {"xrightarrow",         arrow,    3 },
-       {"underleftarrow",      arrow,    1 },
-       {"underrightarrow",     arrow,    3 },
-       {"underleftrightarrow", udarrow,  1 },
+       {"widehat",             angle,        3 },
+       {"widetilde",           tilde,        0 },
+       {"underbar",            hline,        0 },
+       {"underline",           hline,        0 },
+       {"overline",            hline,        0 },
+       {"underbrace",          brace,        1 },
+       {"overbrace",           brace,        3 },
+       {"overleftarrow",       arrow,        1 },
+       {"overrightarrow",      arrow,        3 },
+       {"overleftrightarrow",  udarrow,      1 },
+       {"xhookleftarrow",      lhook,        0 },
+       {"xhookrightarrow",     rhook,        0 },
+       {"xleftarrow",          arrow,        1 },
+       {"xLeftarrow",          LArrow,       0 },
+       {"xleftharpoondown",    lharpoondown, 0 },
+       {"xleftharpoonup",      lharpoonup,   0 },
+       {"xleftrightharpoons",  lrharpoons,   0 },
+       {"xleftrightarrow",     udarrow,      1 },
+       {"xLeftrightarrow",     LRArrow,      0 },
+       {"xmapsto",             mapsto,       0 },
+       {"xrightarrow",         arrow,        3 },
+       {"xRightarrow",         LArrow,       2 },
+       {"xrightharpoondown",   lharpoonup,   2 },
+       {"xrightharpoonup",     lharpoondown, 2 },
+       {"xrightleftharpoons",  rlharpoons,   0 },
+       {"underleftarrow",      arrow,        1 },
+       {"underrightarrow",     arrow,        3 },
+       {"underleftrightarrow", udarrow,      1 },
+       {"undertilde",          tilde,        0 },
+       {"utilde",              tilde,        0 },
 
        // Delimiters
        {"(",              parenth,    0 },
@@ -289,12 +425,20 @@ named_deco_struct deco_table[] = {
        {"rbrace",         brace,      2 },
        {"[",              brack,      0 },
        {"]",              brack,      2 },
+       {"llbracket",      dbrack,     0 },
+       {"rrbracket",      dbrack,     2 },
        {"|",              vert,       0 },
        {"/",              slash,      0 },
        {"slash",          slash,      0 },
        {"vert",           vert,       0 },
+       {"lvert",          vert,       0 },
+       {"rvert",          vert,       0 },
        {"Vert",           Vert,       0 },
+       {"lVert",          Vert,       0 },
+       {"rVert",          Vert,       0 },
        {"'",              slash,      1 },
+       {"<",              angle,      0 },
+       {">",              angle,      2 },
        {"\\",             slash,      1 },
        {"backslash",      slash,      1 },
        {"langle",         angle,      0 },
@@ -313,12 +457,13 @@ named_deco_struct deco_table[] = {
        // Accents
        {"ddot",           ddot,       0 },
        {"dddot",          dddot,      0 },
+       {"ddddot",         ddddot,     0 },
        {"hat",            angle,      3 },
        {"grave",          slash,      1 },
        {"acute",          slash,      0 },
        {"tilde",          tilde,      0 },
        {"bar",            hline,      0 },
-       {"dot",            hlinesmall, 0 },
+       {"dot",            dot,        0 },
        {"check",          angle,      1 },
        {"breve",          parenth,    1 },
        {"vec",            arrow,      3 },
@@ -330,6 +475,8 @@ named_deco_struct deco_table[] = {
        {"cdots",          hline3,     0 },
        {"vdots",          hline3,     1 },
        {"ddots",          dline3,     0 },
+       {"adots",          dline3,     1 },
+       {"iddots",         dline3,     1 },
        {"dotsb",          hline3,     0 },
        {"dotsc",          hline3,     0 },
        {"dotsi",          hline3,     0 },
@@ -354,7 +501,7 @@ public:
        }
 };
 
-static init_deco_table dummy;
+static init_deco_table dummy_deco_table;
 
 
 deco_struct const * search_deco(docstring const & name)
@@ -364,7 +511,52 @@ deco_struct const * search_deco(docstring const & name)
 }
 
 
-} // namespace anon
+} // namespace
+
+
+int mathed_font_em(FontInfo const & font)
+{
+       return theFontMetrics(font).em();
+}
+
+
+int mathed_font_x_height(FontInfo const & font)
+{
+       return theFontMetrics(font).xHeight();
+}
+
+/* The math units. Quoting TeX by Topic, p.205:
+ *
+ * Spacing around mathematical objects is measured in mu units. A mu
+ * is 1/18th part of \fontdimen6 of the font in family 2 in the
+ * current style, the ‘quad’ value of the symbol font.
+ *
+ * A \thickmuskip (default value in plain TeX: 5mu plus 5mu) is
+ * inserted around (binary) relations, except where these are preceded
+ * or followed by other relations or punctuation, and except if they
+ * follow an open, or precede a close symbol.
+ *
+ * A \medmuskip (default value in plain TeX: 4mu plus 2mu minus 4mu)
+ * is put around binary operators.
+ *
+ * A \thinmuskip (default value in plain TeX: 3mu) follows after
+ * punctuation, and is put around inner objects, except where these
+ * are followed by a close or preceded by an open symbol, and except
+ * if the other object is a large operator or a binary relation.
+ *
+ * See the file MathClass.cpp for a formal implementation of the rules
+ * above.
+ */
+
+int mathed_mu(FontInfo const & font, double mu)
+{
+       MetricsBase mb(nullptr, font);
+       return mb.inPixels(Length(mu, Length::MU));
+}
+
+int mathed_thinmuskip(FontInfo const & font) { return mathed_mu(font, 3.0); }
+int mathed_medmuskip(FontInfo const & font) { return mathed_mu(font, 4.0); }
+int mathed_thickmuskip(FontInfo const & font) { return mathed_mu(font, 5.0); }
 
 
 int mathed_char_width(FontInfo const & font, char_type c)
@@ -376,7 +568,7 @@ int mathed_char_width(FontInfo const & font, char_type c)
 int mathed_char_kerning(FontInfo const & font, char_type c)
 {
        frontend::FontMetrics const & fm = theFontMetrics(font);
-       return fm.rbearing(c) - fm.width(c);
+       return max(0, fm.rbearing(c) - fm.width(c));
 }
 
 
@@ -387,11 +579,9 @@ void mathed_string_dim(FontInfo const & font,
        frontend::FontMetrics const & fm = theFontMetrics(font);
        dim.asc = 0;
        dim.des = 0;
-       for (docstring::const_iterator it = s.begin();
-            it != s.end();
-            ++it) {
-               dim.asc = max(dim.asc, fm.ascent(*it));
-               dim.des = max(dim.des, fm.descent(*it));
+       for (char_type const c : s) {
+               dim.asc = max(dim.asc, fm.ascent(c));
+               dim.des = max(dim.des, fm.descent(c));
        }
        dim.wid = fm.width(s);
 }
@@ -406,9 +596,11 @@ int mathed_string_width(FontInfo const & font, docstring const & s)
 void mathed_draw_deco(PainterInfo & pi, int x, int y, int w, int h,
        docstring const & name)
 {
+       int const lw = pi.base.solidLineThickness();
+
        if (name == ".") {
                pi.pain.line(x + w/2, y, x + w/2, y + h,
-                         Color_cursor, Painter::line_onoffdash);
+                         Color_cursor, Painter::line_onoffdash, lw);
                return;
        }
 
@@ -437,7 +629,7 @@ void mathed_draw_deco(PainterInfo & pi, int x, int y, int w, int h,
 
        for (int i = 0; d[i]; ) {
                int code = int(d[i++]);
-               if (code & 1) {  // code == 1 || code == 3
+               if (code & 1) {  // code == 1 || code == 3 || code == 5
                        double xx = d[i++];
                        double yy = d[i++];
                        double x2 = d[i++];
@@ -450,12 +642,56 @@ void mathed_draw_deco(PainterInfo & pi, int x, int y, int w, int h,
                        pi.pain.line(
                                int(x + xx + 0.5), int(y + yy + 0.5),
                                int(x + x2 + 0.5), int(y + y2 + 0.5),
-                               Color_math);
+                               pi.base.font.color(), Painter::line_solid, lw);
+                       if (code == 5) {  // thicker, but rounded
+                               double const xa = x + xx + 0.5;
+                               double const xb = x + x2 + 0.5;
+                               double const ya = y + yy + 0.5;
+                               double const yb = y + y2 + 0.5;
+                               pi.pain.line(int(xa + 1), int(ya - 1),
+                                            int(xb - 1), int(yb - 1),
+                                            pi.base.font.color(),
+                                            Painter::line_solid, lw);
+                               pi.pain.line(int(xa + 1), int(ya + 1),
+                                            int(xb - 1), int(yb + 1),
+                                            pi.base.font.color(),
+                                            Painter::line_solid, lw);
+                               if (xa + 2 <= xb - 2) {
+                                       pi.pain.line(int(xa + 2), int(ya - 2),
+                                                    int(xb - 2), int(yb - 2),
+                                                    pi.base.font.color(),
+                                                    Painter::line_solid, lw);
+                                       pi.pain.line(int(xa + 2), int(ya + 2),
+                                                    int(xb - 2), int(yb + 2),
+                                                    pi.base.font.color(),
+                                                    Painter::line_solid, lw);
+                               }
+                               if (xa + 3 <= xb - 3) {
+                                       pi.pain.line(int(xa + 3), int(ya - 3),
+                                                    int(xb - 3), int(yb - 3),
+                                                    pi.base.font.color(),
+                                                    Painter::line_solid, lw);
+                                       pi.pain.line(int(xa + 3), int(ya + 3),
+                                                    int(xb - 3), int(yb + 3),
+                                                    pi.base.font.color(),
+                                                    Painter::line_solid, lw);
+                               }
+                               if (xa + 4 <= xb - 4) {
+                                       pi.pain.line(int(xa + 4), int(ya - 4),
+                                                    int(xb - 4), int(yb - 4),
+                                                    pi.base.font.color(),
+                                                    Painter::line_solid, lw);
+                                       pi.pain.line(int(xa + 4), int(ya + 4),
+                                                    int(xb - 4), int(yb + 4),
+                                                    pi.base.font.color(),
+                                                    Painter::line_solid, lw);
+                               }
+                       }
                } else {
                        int xp[32];
                        int yp[32];
-                       int const n = int(d[i++]);
-                       for (int j = 0; j < n; ++j) {
+                       int const n2 = int(d[i++]);
+                       for (int j = 0; j < n2; ++j) {
                                double xx = d[i++];
                                double yy = d[i++];
 //          lyxerr << ' ' << xx << ' ' << yy << ' ';
@@ -467,15 +703,79 @@ void mathed_draw_deco(PainterInfo & pi, int x, int y, int w, int h,
                                yp[j] = int(y + yy + 0.5);
                                //  lyxerr << "P[" << j ' ' << xx << ' ' << yy << ' ' << x << ' ' << y << ']';
                        }
-                       pi.pain.lines(xp, yp, n, Color_math);
+                       pi.pain.lines(xp, yp, n2, pi.base.font.color(),
+                               Painter::fill_none, Painter::line_solid, lw);
                }
        }
 }
 
 
+docstring const &  mathedSymbol(MetricsBase & mb, latexkeys const * sym)
+{
+       return (mb.font.style() == DISPLAY_STYLE && !sym->dsp_draw.empty()) ?
+               sym->dsp_draw : sym->draw;
+}
+
+
+int mathedSymbolDim(MetricsBase & mb, Dimension & dim, latexkeys const * sym)
+{
+       LASSERT((bool)sym, return 0);
+       //lyxerr << "metrics: symbol: '" << sym->name
+       //      << "' in font: '" << sym->inset
+       //      << "' drawn as: '" << sym->draw
+       //      << "'" << endl;
+
+       bool const italic_upcase_greek = sym->inset == "cmr" &&
+               sym->extra == "mathalpha" &&
+               mb.fontname == "mathit";
+       std::string const font = italic_upcase_greek ? "cmm" : sym->inset;
+       bool const change_font = font != "cmr" ||
+                               (mb.fontname != "mathbb" &&
+                                mb.fontname != "mathds" &&
+                                mb.fontname != "mathfrak" &&
+                                mb.fontname != "mathcal" &&
+                                mb.fontname != "mathscr");
+       Changer dummy = change_font ? mb.changeFontSet(font) : noChange();
+       mathed_string_dim(mb.font, mathedSymbol(mb, sym), dim);
+       return mathed_char_kerning(mb.font, mathedSymbol(mb, sym).back());
+}
+
+
+void mathedSymbolDraw(PainterInfo & pi, int x, int y, latexkeys const * sym)
+{
+       LASSERT((bool)sym, return);
+       //lyxerr << "drawing: symbol: '" << sym->name
+       //      << "' in font: '" << sym->inset
+       //      << "' drawn as: '" << sym->draw
+       //      << "'" << endl;
+
+       bool const italic_upcase_greek = sym->inset == "cmr" &&
+               sym->extra == "mathalpha" &&
+               pi.base.fontname == "mathit";
+       std::string const font = italic_upcase_greek ? "cmm" : sym->inset;
+       bool const change_font = font != "cmr" ||
+                               (pi.base.fontname != "mathbb" &&
+                                pi.base.fontname != "mathds" &&
+                                pi.base.fontname != "mathfrak" &&
+                                pi.base.fontname != "mathcal" &&
+                                pi.base.fontname != "mathscr");
+       Changer dummy = change_font ? pi.base.changeFontSet(font) : noChange();
+       pi.draw(x, y, mathedSymbol(pi.base, sym));
+}
+
+
+void metricsStrRedBlack(MetricsInfo & mi, Dimension & dim, docstring const & str)
+{
+       FontInfo font = mi.base.font;
+       augmentFont(font, "mathnormal");
+       mathed_string_dim(font, str, dim);
+}
+
+
 void drawStrRed(PainterInfo & pi, int x, int y, docstring const & str)
 {
        FontInfo f = pi.base.font;
+       augmentFont(f, "mathnormal");
        f.setColor(Color_latex);
        pi.pain.text(x, y, str, f);
 }
@@ -484,6 +784,7 @@ void drawStrRed(PainterInfo & pi, int x, int y, docstring const & str)
 void drawStrBlack(PainterInfo & pi, int x, int y, docstring const & str)
 {
        FontInfo f = pi.base.font;
+       augmentFont(f, "mathnormal");
        f.setColor(Color_foreground);
        pi.pain.text(x, y, str, f);
 }
@@ -515,6 +816,7 @@ FontShape  const inh_shape  = INHERIT_SHAPE;
 // does not work
 fontinfo fontinfos[] = {
        // math fonts
+       // Color_math determines which fonts are math (see isMathFont)
        {"mathnormal",    ROMAN_FAMILY, MEDIUM_SERIES,
                          ITALIC_SHAPE, Color_math},
        {"mathbf",        inh_family, BOLD_SERIES,
@@ -529,10 +831,14 @@ fontinfo fontinfos[] = {
                          inh_shape, Color_math},
        {"mathbb",        MSB_FAMILY, inh_series,
                          inh_shape, Color_math},
+       {"mathds",        DS_FAMILY, inh_series,
+                         inh_shape, Color_math},
        {"mathtt",        TYPEWRITER_FAMILY, inh_series,
                          inh_shape, Color_math},
        {"mathit",        inh_family, inh_series,
                          ITALIC_SHAPE, Color_math},
+       {"mathscr",       RSFS_FAMILY, inh_series,
+                         inh_shape, Color_math},
        {"cmex",          CMEX_FAMILY, inh_series,
                          inh_shape, Color_math},
        {"cmm",           CMM_FAMILY, inh_series,
@@ -547,6 +853,8 @@ fontinfo fontinfos[] = {
                          inh_shape, Color_math},
        {"msb",           MSB_FAMILY, inh_series,
                          inh_shape, Color_math},
+       {"stmry",         STMARY_FAMILY, inh_series,
+                         inh_shape, Color_math},
        {"wasy",          WASY_FAMILY, inh_series,
                          inh_shape, Color_math},
        {"esint",         ESINT_FAMILY, inh_series,
@@ -580,9 +888,18 @@ fontinfo fontinfos[] = {
        {"textipa",       inh_family, inh_series,
                          inh_shape, Color_foreground},
 
+       // mhchem support
+       {"ce",            inh_family, inh_series,
+                         inh_shape, Color_foreground},
+       {"cf",            inh_family, inh_series,
+                         inh_shape, Color_foreground},
+
        // LyX internal usage
        {"lyxtex",        inh_family, inh_series,
                          UP_SHAPE, Color_latex},
+       // FIXME: The following two don't work on OS X, since the Symbol font
+       //        uses a different encoding, and is therefore disabled in
+       //        FontLoader::available().
        {"lyxsymbol",     SYMBOL_FAMILY, inh_series,
                          inh_shape, Color_math},
        {"lyxboldsymbol", SYMBOL_FAMILY, BOLD_SERIES,
@@ -600,11 +917,10 @@ fontinfo fontinfos[] = {
 };
 
 
-fontinfo * lookupFont(docstring const & name0)
+fontinfo * lookupFont(string const & name)
 {
        //lyxerr << "searching font '" << name << "'" << endl;
        int const n = sizeof(fontinfos) / sizeof(fontinfo);
-       string name = to_utf8(name0);
        for (int i = 0; i < n; ++i)
                if (fontinfos[i].cmd_ == name) {
                        //lyxerr << "found '" << i << "'" << endl;
@@ -614,7 +930,7 @@ fontinfo * lookupFont(docstring const & name0)
 }
 
 
-fontinfo * searchFont(docstring const & name)
+fontinfo * searchFont(string const & name)
 {
        fontinfo * f = lookupFont(name);
        return f ? f : fontinfos;
@@ -623,13 +939,27 @@ fontinfo * searchFont(docstring const & name)
 }
 
 
-bool isFontName(docstring const & name)
+bool isFontName(string const & name)
 {
        return lookupFont(name);
 }
 
 
-FontInfo getFont(docstring const & name)
+bool isMathFont(string const & name)
+{
+       fontinfo * f = lookupFont(name);
+       return f && f->color_ == Color_math;
+}
+
+
+bool isTextFont(string const & name)
+{
+       fontinfo * f = lookupFont(name);
+       return f && f->color_ == Color_foreground;
+}
+
+
+FontInfo getFont(string const & name)
 {
        FontInfo font;
        augmentFont(font, name);
@@ -637,7 +967,7 @@ FontInfo getFont(docstring const & name)
 }
 
 
-void fakeFont(docstring const & orig, docstring const & fake)
+void fakeFont(string const & orig, string const & fake)
 {
        fontinfo * forig = searchFont(orig);
        fontinfo * ffake = searchFont(fake);
@@ -647,22 +977,22 @@ void fakeFont(docstring const & orig, docstring const & fake)
                forig->shape_  = ffake->shape_;
                forig->color_  = ffake->color_;
        } else {
-               lyxerr << "Can't fake font '" << to_utf8(orig) << "' with '"
-                      << to_utf8(fake) << "'" << endl;
+               lyxerr << "Can't fake font '" << orig << "' with '"
+                      << fake << "'" << endl;
        }
 }
 
 
-void augmentFont(FontInfo & font, docstring const & name)
+void augmentFont(FontInfo & font, string const & name)
 {
        static bool initialized = false;
        if (!initialized) {
                initialized = true;
                // fake fonts if necessary
-               if (!theFontLoader().available(getFont(from_ascii("mathfrak"))))
-                       fakeFont(from_ascii("mathfrak"), from_ascii("lyxfakefrak"));
-               if (!theFontLoader().available(getFont(from_ascii("mathcal"))))
-                       fakeFont(from_ascii("mathcal"), from_ascii("lyxfakecal"));
+               if (!theFontLoader().available(getFont("mathfrak")))
+                       fakeFont("mathfrak", "lyxfakefrak");
+               if (!theFontLoader().available(getFont("mathcal")))
+                       fakeFont("mathcal", "lyxfakecal");
        }
        fontinfo * info = searchFont(name);
        if (info->family_ != inh_family)
@@ -676,10 +1006,32 @@ void augmentFont(FontInfo & font, docstring const & name)
 }
 
 
+bool isAlphaSymbol(MathAtom const & at)
+{
+       if (at->asCharInset() ||
+           (at->asSymbolInset() &&
+            at->asSymbolInset()->isOrdAlpha()))
+               return true;
+
+       if (at->asFontInset()) {
+               MathData const & ar = at->asFontInset()->cell(0);
+               for (size_t i = 0; i < ar.size(); ++i) {
+                       if (!(ar[i]->asCharInset() ||
+                             (ar[i]->asSymbolInset() &&
+                              ar[i]->asSymbolInset()->isOrdAlpha())))
+                               return false;
+               }
+               return true;
+       }
+       return false;
+}
+
+
 docstring asString(MathData const & ar)
 {
        odocstringstream os;
-       WriteStream ws(os);
+       otexrowstream ots(os);
+       TeXMathStream ws(ots);
        ws << ar;
        return os.str();
 }
@@ -687,8 +1039,13 @@ docstring asString(MathData const & ar)
 
 void asArray(docstring const & str, MathData & ar, Parse::flags pf)
 {
+       // If the QUIET flag is set, we are going to parse for either
+       // a paste operation or a macro definition. We try to do the
+       // right thing in all cases.
+
        bool quiet = pf & Parse::QUIET;
-       if ((str.size() == 1 && quiet) || (!mathed_parse_cell(ar, str, pf) && quiet))
+       bool macro = pf & Parse::MACRODEF;
+       if ((str.size() == 1 && quiet) || (!mathed_parse_cell(ar, str, pf) && quiet && !macro))
                mathed_parse_cell(ar, str, pf | Parse::VERBATIM);
 }
 
@@ -696,7 +1053,8 @@ void asArray(docstring const & str, MathData & ar, Parse::flags pf)
 docstring asString(InsetMath const & inset)
 {
        odocstringstream os;
-       WriteStream ws(os);
+       otexrowstream ots(os);
+       TeXMathStream ws(ots);
        inset.write(ws);
        return os.str();
 }
@@ -705,10 +1063,30 @@ docstring asString(InsetMath const & inset)
 docstring asString(MathAtom const & at)
 {
        odocstringstream os;
-       WriteStream ws(os);
+       otexrowstream ots(os);
+       TeXMathStream ws(ots);
        at->write(ws);
        return os.str();
 }
 
 
+int axis_height(MetricsBase & mb)
+{
+       Changer dummy = mb.changeFontSet("mathnormal");
+       return theFontMetrics(mb.font).ascent('-') - 1;
+}
+
+
+void validate_math_word(LaTeXFeatures & features, docstring const & word)
+{
+       MathWordList const & words = mathedWordList();
+       MathWordList::const_iterator it = words.find(word);
+       if (it != words.end()) {
+               string const req = it->second.required;
+               if (!req.empty())
+                       features.require(req);
+       }
+}
+
+
 } // namespace lyx