/* This file is part of * ====================================================== * * LyX, The Document Processor * * Copyright 1995 Matthias Ettrich * Copyright 1995-1999 The LyX Team. * * ====================================================== */ #include #include #ifdef __GNUG__ #pragma implementation "lyxfont.h" #endif #include #include "gettext.h" #include "lyxfont.h" #include "debug.h" #include "lyxrc.h" #include "lyxlex.h" #include "lyxdraw.h" #include "FontLoader.h" #include "support/lstrings.h" extern LyXRC * lyxrc; // The global fontloader FontLoader fontloader; // // Names for the GUI // string const GUIFamilyNames[6] = { N_("Roman"), N_("Sans serif"), N_("Typewriter"), N_("Symbol"), N_("Inherit"), N_("Ignore") }; string const GUISeriesNames[4] = { N_("Medium"), N_("Bold"), N_("Inherit"), N_("Ignore") }; string const GUIShapeNames[6] = { N_("Upright"), N_("Italic"), N_("Slanted"), N_("Smallcaps"), N_("Inherit"), N_("Ignore") }; string const GUISizeNames[14] = { N_("Tiny"), N_("Smallest"), N_("Smaller"), N_("Small"), N_("Normal"), N_("Large"), N_("Larger"), N_("Largest"), N_("Huge"), N_("Huger"), N_("Increase"), N_("Decrease"), N_("Inherit"), N_("Ignore") }; string const lGUISizeNames[15] = { N_("tiny"), N_("smallest"), N_("smaller"), N_("small"), N_("normal"), N_("large"), N_("larger"), N_("largest"), N_("huge"), N_("huger"), N_("increase"), N_("decrease"), N_("inherit"), N_("ignore"), string() }; string const GUIMiscNames[5] = { N_("Off"), N_("On"), N_("Toggle"), N_("Inherit"), N_("Ignore") }; string const GUIColorNames[13] = { N_("None"), N_("Black"), N_("White"), N_("Red"), N_("Green"), N_("Blue"), N_("Cyan"), N_("Magenta"), N_("Yellow"), N_("Math"), N_("Inset"), N_("Inherit"), N_("Ignore") }; // // Strings used to read and write .lyx format files // string const LyXFamilyNames[6] = { "roman", "sans", "typewriter", "symbol", "default", "error" }; string const LyXSeriesNames[4] = { "medium", "bold", "default", "error" }; string const LyXShapeNames[6] = { "up", "italic", "slanted", "smallcaps", "default", "error" }; string const LyXSizeNames[14] = { "tiny", "scriptsize", "footnotesize", "small", "normal", "large", "larger", "largest", "huge", "giant", "increase-error", "decrease-error", "default", "error" }; string const LyXMiscNames[12] = { "off", "on", "toggle", "default", "error" }; string const LyXColorNames[13] = { "none", "black", "white", "red", "green", "blue", "cyan", "magenta", "yellow", "matherror", "inseterror", "default", "error" }; // // Strings used to write LaTeX files // string const LaTeXFamilyNames[6] = { "textrm", "textsf", "texttt", "error1", "error2", "error3" }; string const LaTeXSeriesNames[4] = { "textmd", "textbf", "error4", "error5" }; string const LaTeXShapeNames[6] = { "textup", "textit", "textsl", "textsc", "error6", "error7" }; string const LaTeXSizeNames[14] = { "tiny", "scriptsize", "footnotesize", "small", "normalsize", "large", "Large", "LARGE", "huge", "Huge", "error8", "error9", "error10", "error11" }; string const LaTeXColorNames[13] = { "none", "black", "white", "red", "green", "blue", "cyan", "magenta", "yellow", "error12", "error13", "error14", "error15" }; /// Decreases font size by one LyXFont & LyXFont::decSize() { switch (size()) { case SIZE_HUGER: setSize(SIZE_HUGE); break; case SIZE_HUGE: setSize(SIZE_LARGEST); break; case SIZE_LARGEST: setSize(SIZE_LARGER); break; case SIZE_LARGER: setSize(SIZE_LARGE); break; case SIZE_LARGE: setSize(SIZE_NORMAL); break; case SIZE_NORMAL: setSize(SIZE_SMALL); break; case SIZE_SMALL: setSize(SIZE_FOOTNOTE); break; case SIZE_FOOTNOTE: setSize(SIZE_SCRIPT); break; case SIZE_SCRIPT: setSize(SIZE_TINY); break; case SIZE_TINY: break; case INCREASE_SIZE: lyxerr << "Can't LyXFont::decSize on INCREASE_SIZE" << endl; break; case DECREASE_SIZE: lyxerr <<"Can't LyXFont::decSize on DECREASE_SIZE" << endl; break; case INHERIT_SIZE: lyxerr <<"Can't LyXFont::decSize on INHERIT_SIZE" << endl; break; case IGNORE_SIZE: lyxerr <<"Can't LyXFont::decSize on IGNORE_SIZE" << endl; break; } return (*this); } /// Increases font size by one LyXFont & LyXFont::incSize() { switch(size()) { case SIZE_HUGER: break; case SIZE_HUGE: setSize(SIZE_HUGER); break; case SIZE_LARGEST: setSize(SIZE_HUGE); break; case SIZE_LARGER: setSize(SIZE_LARGEST); break; case SIZE_LARGE: setSize(SIZE_LARGER); break; case SIZE_NORMAL: setSize(SIZE_LARGE); break; case SIZE_SMALL: setSize(SIZE_NORMAL); break; case SIZE_FOOTNOTE: setSize(SIZE_SMALL); break; case SIZE_SCRIPT: setSize(SIZE_FOOTNOTE); break; case SIZE_TINY: setSize(SIZE_SCRIPT); break; case INCREASE_SIZE: lyxerr <<"Can't LyXFont::incSize on INCREASE_SIZE" << endl; break; case DECREASE_SIZE: lyxerr <<"Can't LyXFont::incSize on DECREASE_SIZE" << endl; break; case INHERIT_SIZE: lyxerr <<"Can't LyXFont::incSize on INHERIT_SIZE" << endl; break; case IGNORE_SIZE: lyxerr <<"Can't LyXFont::incSize on IGNORE_SIZE" << endl; break; } return (*this); } /// Updates a misc setting according to request LyXFont::FONT_MISC_STATE LyXFont::setMisc(FONT_MISC_STATE newfont, FONT_MISC_STATE org) { if (newfont == TOGGLE) { if (org == ON) return OFF; else if (org == OFF) return ON; else { lyxerr <<"LyXFont::setMisc: Need state" " ON or OFF to toggle. Setting to ON" << endl; return ON; } } else if (newfont == IGNORE) return org; else return newfont; } /// Updates font settings according to request void LyXFont::update(LyXFont const & newfont, bool toggleall) { if(newfont.family() == family() && toggleall) setFamily(INHERIT_FAMILY); // toggle 'back' else if (newfont.family() != IGNORE_FAMILY) setFamily(newfont.family()); // else it's IGNORE_SHAPE // "Old" behaviour: "Setting" bold will toggle bold on/off. switch (newfont.series()) { case BOLD_SERIES: // We toggle... if (series() == BOLD_SERIES && toggleall) setSeries(MEDIUM_SERIES); else setSeries(BOLD_SERIES); break; case MEDIUM_SERIES: case INHERIT_SERIES: setSeries(newfont.series()); break; case IGNORE_SERIES: break; } if(newfont.shape() == shape() && toggleall) setShape(INHERIT_SHAPE); // toggle 'back' else if (newfont.shape() != IGNORE_SHAPE) setShape(newfont.shape()); // else it's IGNORE_SHAPE if (newfont.size() != IGNORE_SIZE) { if (newfont.size() == INCREASE_SIZE) incSize(); else if (newfont.size() == DECREASE_SIZE) decSize(); else if (newfont.size() == size() && toggleall) setSize(INHERIT_SIZE); // toggle 'back' else setSize(newfont.size()); } setEmph(setMisc(newfont.emph(), emph())); setUnderbar(setMisc(newfont.underbar(), underbar())); setNoun(setMisc(newfont.noun(), noun())); setLatex(setMisc(newfont.latex(), latex())); if(newfont.color() == color() && toggleall) setColor(INHERIT_COLOR); // toggle 'back' else if (newfont.color() != IGNORE_COLOR) setColor(newfont.color()); } /// Reduce font to fall back to template where possible void LyXFont::reduce(LyXFont const & tmplt) { if (family() == tmplt.family()) setFamily(INHERIT_FAMILY); if (series() == tmplt.series()) setSeries(INHERIT_SERIES); if (shape() == tmplt.shape()) setShape(INHERIT_SHAPE); if (size() == tmplt.size()) setSize(INHERIT_SIZE); if (emph() == tmplt.emph()) setEmph(INHERIT); if (underbar() == tmplt.underbar()) setUnderbar(INHERIT); if (noun() == tmplt.noun()) setNoun(INHERIT); if (latex() == tmplt.latex()) setLatex(INHERIT); if (color() == tmplt.color()) setColor(INHERIT_COLOR); } /// Realize font from a template // This one is not pretty, but it's extremely fast (Asger) LyXFont & LyXFont::realize(LyXFont const & tmplt) { if (bits == inherit) { bits = tmplt.bits; return *this; } if ((bits & (Fam_Mask<fid); return gc; } XFontStruct * LyXFont::getXFontstruct() const { return fontloader.load(family(), series(), realShape(), size()); } int LyXFont::maxAscent() const { return getXFontstruct()->ascent; } int LyXFont::maxDescent() const { return getXFontstruct()->descent; } int LyXFont::ascent(char c) const { XFontStruct * finfo = getXFontstruct(); if (finfo->per_char && static_cast(c) >= finfo->min_char_or_byte2 && static_cast(c) <= finfo->max_char_or_byte2) { unsigned int index = c - finfo->min_char_or_byte2; return finfo->per_char[index].ascent; } else return finfo->ascent; } int LyXFont::descent(char c) const { XFontStruct * finfo = getXFontstruct(); if (finfo->per_char && static_cast(c) >= finfo->min_char_or_byte2 && static_cast(c) <= finfo->max_char_or_byte2) { unsigned int index = c - finfo->min_char_or_byte2; return finfo->per_char[index].descent; } else return finfo->descent; } // Specialized after profiling. (Asger) int LyXFont::width(char c) const { if (realShape() != LyXFont::SMALLCAPS_SHAPE){ return XTextWidth(getXFontstruct(), &c, 1); } else { return textWidth(&c, 1); } } int LyXFont::lbearing(char c) const { XFontStruct * finfo = getXFontstruct(); if (finfo->per_char && static_cast(c) >= finfo->min_char_or_byte2 && static_cast(c) <= finfo->max_char_or_byte2) { unsigned int index = c - finfo->min_char_or_byte2; return finfo->per_char[index].lbearing; } else return 0; } int LyXFont::rbearing(char c) const { XFontStruct * finfo = getXFontstruct(); if (finfo->per_char && static_cast(c) >= finfo->min_char_or_byte2 && static_cast(c) <= finfo->max_char_or_byte2) { unsigned int index = c - finfo->min_char_or_byte2; return finfo->per_char[index].rbearing; } else return width(c); } int LyXFont::textWidth(char const * s, int n) const { if (realShape() != LyXFont::SMALLCAPS_SHAPE){ return XTextWidth(getXFontstruct(), s, n); } else { // emulate smallcaps since X doesn't support this unsigned int result = 0; char c; LyXFont smallfont = *this; smallfont.decSize(); smallfont.decSize(); smallfont.setShape(LyXFont::UP_SHAPE); for (int i = 0; i < n; ++i) { c = s[i]; if (islower(c)){ c = toupper(c); result += XTextWidth(smallfont.getXFontstruct(), &c, 1); } else { result += XTextWidth(getXFontstruct(), &c, 1); } } return result; } } int LyXFont::stringWidth(string const & s) const { if (s.empty()) return 0; return textWidth(s.c_str(), s.length()); } int LyXFont::signedStringWidth(string const & s) const { if (s.empty()) return 0; if (s.c_str()[0] == '-') return -textWidth(s.c_str()+1, s.length()-1); else return textWidth(s.c_str(), s.length()); } int LyXFont::drawText(char const * s, int n, Pixmap pm, int baseline, int x) const { if (realShape() != LyXFont::SMALLCAPS_SHAPE) { XDrawString(fl_display, pm, getGC(), x, baseline, s, n); XFlush(fl_display); return XTextWidth(getXFontstruct(), s, n); } else { // emulate smallcaps since X doesn't support this char c; int sx = x; LyXFont smallfont = *this; smallfont.decSize(); smallfont.decSize(); smallfont.setShape(LyXFont::UP_SHAPE); for (int i = 0; i < n; ++i) { c = s[i]; if (islower(c)){ c = toupper(c); XDrawString(fl_display, pm, smallfont.getGC(), x, baseline, &c, 1); x += XTextWidth(smallfont.getXFontstruct(), &c, 1); XFlush(fl_display); } else { XDrawString(fl_display, pm, getGC(), x, baseline, &c, 1); x += XTextWidth(getXFontstruct(), &c, 1); XFlush(fl_display); } } return x - sx; } } int LyXFont::drawString(string const & s, Pixmap pm, int baseline, int x) const { return drawText(s.c_str(), s.length(), pm, baseline, x); } bool LyXFont::equalExceptLatex(LyXFont const & f) const { LyXFont f1 = *this; f1.setLatex(f.latex()); return f1 == f; } ostream & operator<<(ostream & o, LyXFont::FONT_MISC_STATE fms) { return o << int(fms); }