Math: add a structure to hold font information.

It will allow to merge a lot of code for MathML and HTML: same parsing, slightly different outputs. The refactoring also shows clearly what parts are missing in HTML (while being easily fixable). The change is a prerequisite for implementing font nesting (although it is not done yet).

The new class is not yet used within InsetMathFont; it will come in the next commit.

Open question: should we use InsetMath::mode_type somewhere? I believe so, to determine whether the current default is italics or not in MathML.
This commit is contained in:
Thibaut Cuvelier 2024-10-29 04:06:07 +01:00
parent 91a85dd96a
commit 9a81bb36f4

View File

@ -28,6 +28,151 @@ using namespace lyx::support;
namespace lyx { namespace lyx {
namespace {
// Similar to FontInfo and its related enums, but specifically for the math
// mode.
//
// All types have enumerations, like FontEnums.h, even though there are
// sometimes only two cases: this design ensures some future-proofness and
// ensures that you cannot inadvertently swap two values.
class MathFontInfo {
public:
enum MathFontFamily {
MATH_NORMAL_FAMILY = 0, // Default value in MathML.
MATH_FRAKTUR_FAMILY,
MATH_SANS_FAMILY,
MATH_MONOSPACE_FAMILY,
MATH_DOUBLE_STRUCK_FAMILY,
MATH_SCRIPT_FAMILY,
MATH_SMALL_CAPS // Not natively supported in any version of MathML.
};
enum MathFontSeries {
MATH_MEDIUM_SERIES = 0, // Default value in MathML. // Default value in MathML.
MATH_BOLD_SERIES
};
enum MathFontShape {
MATH_UP_SHAPE = 0,
MATH_ITALIC_SHAPE // Default value in MathML mi, not outside.
};
MathFontInfo() :
family_(MATH_NORMAL_FAMILY), series_(MATH_MEDIUM_SERIES), shape_(MATH_UP_SHAPE) {}
MathFontInfo(const MathFontFamily family, const MathFontSeries series, const MathFontShape shape) :
family_(family), series_(series), shape_(shape) {}
static MathFontInfo fromMacro(const docstring& tag)
{
MathFontInfo font;
if (tag == "mathnormal" || tag == "mathrm"
|| tag == "text" || tag == "textnormal"
|| tag == "textrm" || tag == "textup"
|| tag == "textmd")
font.shape_ = MATH_UP_SHAPE;
else if (tag == "frak" || tag == "mathfrak")
font.family_ = MATH_FRAKTUR_FAMILY;
else if (tag == "mathbf" || tag == "textbf")
font.series_ = MATH_BOLD_SERIES;
else if (tag == "mathbb" || tag == "mathbbm"
|| tag == "mathds")
font.family_ = MATH_DOUBLE_STRUCK_FAMILY;
else if (tag == "mathcal")
font.family_ = MATH_SCRIPT_FAMILY;
else if (tag == "mathit" || tag == "textsl"
|| tag == "emph" || tag == "textit")
font.shape_ = MATH_ITALIC_SHAPE;
else if (tag == "mathsf" || tag == "textsf")
font.family_ = MATH_SANS_FAMILY;
else if (tag == "mathtt" || tag == "texttt")
font.family_ = MATH_MONOSPACE_FAMILY;
else if (tag == "textipa" || tag == "textsc" || tag == "noun")
font.family_ = MATH_SMALL_CAPS;
return font;
}
MathFontFamily family() const { return family_; }
MathFontSeries series() const { return series_; }
MathFontShape shape() const { return shape_; }
std::string toMathMLMathVariant(MathMLStream::MathMLVersion mathml_version) const
{
return mathml_version == MathMLStream::MathMLVersion::mathml3 ?
toMathVariantForMathML3() : toMathVariantForMathMLCore();
}
std::string toHTMLSpanClass() const
{
// See the existing classes in InsetMathFont::validate. In particular,
// there is no double-struck style!
switch (family_) {
case MATH_MONOSPACE_FAMILY:
return "monospace";
case MATH_FRAKTUR_FAMILY:
return "fraktur";
case MATH_SCRIPT_FAMILY:
return "script";
case MATH_SMALL_CAPS:
return "noun";
case MATH_SANS_FAMILY:
return "sans";
case MATH_NORMAL_FAMILY:
if (series_ == MATH_MEDIUM_SERIES) {
return shape_ == MATH_UP_SHAPE ? "normal" : "italic";
}
return "bold";
case MATH_DOUBLE_STRUCK_FAMILY:
// No support for double-struck font in CSS.
return "";
}
}
private:
MathFontFamily family_;
MathFontSeries series_;
MathFontShape shape_;
std::string toMathVariantForMathML3() const
{
// mathvariant is the way MathML 3 encodes fonts.
// Not all combinations are supported. Official list:
// https://www.w3.org/TR/MathML3/chapter3.html#presm.commatt
// "initial", "tailed", "looped", and "stretched" are not implemented,
// as they are only useful for Arabic characters (for which LyX has no
// support right now).
switch (family_) {
case MATH_MONOSPACE_FAMILY:
return "monospace";
case MATH_DOUBLE_STRUCK_FAMILY:
return "double-struck";
case MATH_FRAKTUR_FAMILY:
return series_ == MATH_BOLD_SERIES ? "bold-fraktur" : "fraktur";
case MATH_SCRIPT_FAMILY:
return series_ == MATH_BOLD_SERIES ? "bold-script" : "script";
case MATH_SANS_FAMILY:
if (series_ == MATH_MEDIUM_SERIES) {
return shape_ == MATH_UP_SHAPE ? "sans-serif" : "sans-serif-italic";
}
return shape_ == MATH_UP_SHAPE ? "bold-sans-serif" : "sans-serif-bold-italic";
case MATH_NORMAL_FAMILY:
if (series_ == MATH_MEDIUM_SERIES) {
return shape_ == MATH_UP_SHAPE ? "normal" : "italic";
}
return shape_ == MATH_UP_SHAPE ? "bold" : "bold-italic";
case MATH_SMALL_CAPS:
// No valid value...
return "";
}
}
std::string toMathVariantForMathMLCore() const
{
return shape_ == MATH_UP_SHAPE ? "normal" : "";
}
};
}
InsetMathFont::InsetMathFont(Buffer * buf, latexkeys const * key) InsetMathFont::InsetMathFont(Buffer * buf, latexkeys const * key)
: InsetMathNest(buf, 1), key_(key) : InsetMathNest(buf, 1), key_(key)
{} {}