2 * \file src/FontInfo.cpp
3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
6 * \author Lars Gullik Bjønnes
7 * \author Jean-Marc Lasgouttes
8 * \author Angus Leeming
12 * Full author contact details are available in file CREDITS.
22 #include "support/convert.h"
23 #include "support/debug.h"
24 #include "support/docstring.h"
25 #include "support/lstrings.h"
26 #include "support/RefChanger.h"
33 using namespace lyx::support;
38 // Strings used to read and write .lyx format files
40 char const * LyXFamilyNames[NUM_FAMILIES + 2 /* default & error */] =
41 { "roman", "sans", "typewriter", "symbol",
42 "cmr", "cmsy", "cmm", "cmex", "msa", "msb", "eufrak", "rsfs", "stmry",
43 "wasy", "esint", "default", "error" };
45 char const * LyXSeriesNames[NUM_SERIES + 2 /* default & error */] =
46 { "medium", "bold", "default", "error" };
48 char const * LyXShapeNames[NUM_SHAPE + 2 /* default & error */] =
49 { "up", "italic", "slanted", "smallcaps", "default", "error" };
51 char const * LyXSizeNames[NUM_SIZE + 4 /* increase, decrease, default & error */] =
52 { "tiny", "scriptsize", "footnotesize", "small", "normal", "large",
53 "larger", "largest", "huge", "giant",
54 "increase", "decrease", "default", "error" };
56 char const * LyXMiscNames[5] =
57 { "off", "on", "toggle", "default", "error" };
60 FontInfo const sane_font(
77 FontInfo const inherit_font(
94 FontInfo const ignore_font(
118 /// Decreases font size_ by one
119 FontInfo & FontInfo::decSize()
122 case FONT_SIZE_HUGER: size_ = FONT_SIZE_HUGE; break;
123 case FONT_SIZE_HUGE: size_ = FONT_SIZE_LARGEST; break;
124 case FONT_SIZE_LARGEST: size_ = FONT_SIZE_LARGER; break;
125 case FONT_SIZE_LARGER: size_ = FONT_SIZE_LARGE; break;
126 case FONT_SIZE_LARGE: size_ = FONT_SIZE_NORMAL; break;
127 case FONT_SIZE_NORMAL: size_ = FONT_SIZE_SMALL; break;
128 case FONT_SIZE_SMALL: size_ = FONT_SIZE_FOOTNOTE; break;
129 case FONT_SIZE_FOOTNOTE: size_ = FONT_SIZE_SCRIPT; break;
130 case FONT_SIZE_SCRIPT: size_ = FONT_SIZE_TINY; break;
131 case FONT_SIZE_TINY: break;
132 case FONT_SIZE_INCREASE:
133 LYXERR0("Can't FontInfo::decSize on FONT_SIZE_INCREASE");
135 case FONT_SIZE_DECREASE:
136 LYXERR0("Can't FontInfo::decSize on FONT_SIZE_DECREASE");
138 case FONT_SIZE_INHERIT:
139 LYXERR0("Can't FontInfo::decSize on FONT_SIZE_INHERIT");
141 case FONT_SIZE_IGNORE:
142 LYXERR0("Can't FontInfo::decSize on FONT_SIZE_IGNORE");
149 /// Increases font size_ by one
150 FontInfo & FontInfo::incSize()
153 case FONT_SIZE_HUGER: break;
154 case FONT_SIZE_HUGE: size_ = FONT_SIZE_HUGER; break;
155 case FONT_SIZE_LARGEST: size_ = FONT_SIZE_HUGE; break;
156 case FONT_SIZE_LARGER: size_ = FONT_SIZE_LARGEST; break;
157 case FONT_SIZE_LARGE: size_ = FONT_SIZE_LARGER; break;
158 case FONT_SIZE_NORMAL: size_ = FONT_SIZE_LARGE; break;
159 case FONT_SIZE_SMALL: size_ = FONT_SIZE_NORMAL; break;
160 case FONT_SIZE_FOOTNOTE: size_ = FONT_SIZE_SMALL; break;
161 case FONT_SIZE_SCRIPT: size_ = FONT_SIZE_FOOTNOTE; break;
162 case FONT_SIZE_TINY: size_ = FONT_SIZE_SCRIPT; break;
163 case FONT_SIZE_INCREASE:
164 LYXERR0("Can't FontInfo::incSize on FONT_SIZE_INCREASE");
166 case FONT_SIZE_DECREASE:
167 LYXERR0("Can't FontInfo::incSize on FONT_SIZE_DECREASE");
169 case FONT_SIZE_INHERIT:
170 LYXERR0("Can't FontInfo::incSize on FONT_SIZE_INHERIT");
172 case FONT_SIZE_IGNORE:
173 LYXERR0("Can't FontInfo::incSize on FONT_SIZE_IGNORE");
180 double FontInfo::realSize() const
182 double d = convert<double>(lyxrc.font_sizes[size()]);
183 // The following is according to the average of the values in the
184 // definitions of \defaultscriptratio and \defaultscriptscriptratio in LaTeX
185 // font packages. No attempt is made to implement the actual values from
194 case LM_ST_SCRIPTSCRIPT:
198 // Never go below the smallest size
199 return max(d, convert<double>(lyxrc.font_sizes[FONT_SIZE_TINY]));
203 /// Reduce font to fall back to template where possible
204 void FontInfo::reduce(FontInfo const & tmplt)
206 if (family_ == tmplt.family_)
207 family_ = INHERIT_FAMILY;
208 if (series_ == tmplt.series_)
209 series_ = INHERIT_SERIES;
210 if (shape_ == tmplt.shape_)
211 shape_ = INHERIT_SHAPE;
212 if (size_ == tmplt.size_)
213 size_ = FONT_SIZE_INHERIT;
214 if (emph_ == tmplt.emph_)
215 emph_ = FONT_INHERIT;
216 if (underbar_ == tmplt.underbar_)
217 underbar_ = FONT_INHERIT;
218 if (strikeout_ == tmplt.strikeout_)
219 strikeout_ = FONT_INHERIT;
220 if (xout_ == tmplt.xout_)
221 xout_ = FONT_INHERIT;
222 if (uuline_ == tmplt.uuline_)
223 uuline_ = FONT_INHERIT;
224 if (uwave_ == tmplt.uwave_)
225 uwave_ = FONT_INHERIT;
226 if (noun_ == tmplt.noun_)
227 noun_ = FONT_INHERIT;
228 if (color_ == tmplt.color_)
229 color_ = Color_inherit;
230 if (background_ == tmplt.background_)
231 background_ = Color_inherit;
232 if (nospellcheck_ == tmplt.nospellcheck_)
233 nospellcheck_ = FONT_INHERIT;
237 /// Realize font from a template
238 FontInfo & FontInfo::realize(FontInfo const & tmplt)
240 if ((*this) == inherit_font) {
245 if (family_ == INHERIT_FAMILY)
246 family_ = tmplt.family_;
248 if (series_ == INHERIT_SERIES)
249 series_ = tmplt.series_;
251 if (shape_ == INHERIT_SHAPE)
252 shape_ = tmplt.shape_;
254 if (size_ == FONT_SIZE_INHERIT)
257 if (emph_ == FONT_INHERIT)
260 if (underbar_ == FONT_INHERIT)
261 underbar_ = tmplt.underbar_;
263 if (strikeout_ == FONT_INHERIT)
264 strikeout_ = tmplt.strikeout_;
266 if (xout_ == FONT_INHERIT)
269 if (uuline_ == FONT_INHERIT)
270 uuline_ = tmplt.uuline_;
272 if (uwave_ == FONT_INHERIT)
273 uwave_ = tmplt.uwave_;
275 if (noun_ == FONT_INHERIT)
278 if (color_ == Color_inherit)
279 color_ = tmplt.color_;
281 if (background_ == Color_inherit)
282 background_ = tmplt.background_;
284 if (nospellcheck_ == FONT_INHERIT)
285 nospellcheck_ = tmplt.nospellcheck_;
291 Changer FontInfo::changeColor(ColorCode const color)
293 return make_change(color_, color);
297 Changer FontInfo::changeShape(FontShape const shape)
299 return make_change(shape_, shape);
303 Changer FontInfo::changeStyle(MathStyle const new_style)
305 return make_change(style_, new_style);
309 Changer FontInfo::change(FontInfo font, bool realiz)
313 return make_change(*this, font);
317 /// Updates a misc setting according to request
318 static FontState setMisc(FontState newfont,
321 if (newfont == FONT_TOGGLE) {
324 else if (org == FONT_OFF)
327 LYXERR0("Font::setMisc: Need state"
328 " FONT_ON or FONT_OFF to toggle. Setting to FONT_ON");
331 } else if (newfont == FONT_IGNORE)
337 /// Updates font settings according to request
338 void FontInfo::update(FontInfo const & newfont, bool toggleall)
340 if (newfont.family_ == family_ && toggleall)
341 setFamily(INHERIT_FAMILY); // toggle 'back'
342 else if (newfont.family_ != IGNORE_FAMILY)
343 setFamily(newfont.family_);
344 // else it's IGNORE_SHAPE
346 // "Old" behaviour: "Setting" bold will toggle bold on/off.
347 switch (newfont.series_) {
350 if (series_ == BOLD_SERIES && toggleall)
351 setSeries(MEDIUM_SERIES);
353 setSeries(BOLD_SERIES);
357 setSeries(newfont.series_);
363 if (newfont.shape_ == shape_ && toggleall)
364 shape_ = INHERIT_SHAPE; // toggle 'back'
365 else if (newfont.shape_ != IGNORE_SHAPE)
366 shape_ = newfont.shape_;
367 // else it's IGNORE_SHAPE
369 if (newfont.size_ != FONT_SIZE_IGNORE) {
370 if (newfont.size_ == FONT_SIZE_INCREASE)
372 else if (newfont.size_ == FONT_SIZE_DECREASE)
375 size_ = newfont.size_;
378 setEmph(setMisc(newfont.emph_, emph_));
379 setUnderbar(setMisc(newfont.underbar_, underbar_));
380 setStrikeout(setMisc(newfont.strikeout_, strikeout_));
381 setXout(setMisc(newfont.xout_, xout_));
382 setUuline(setMisc(newfont.uuline_, uuline_));
383 setUwave(setMisc(newfont.uwave_, uwave_));
384 setNoun(setMisc(newfont.noun_, noun_));
385 setNumber(setMisc(newfont.number_, number_));
386 setNoSpellcheck(setMisc(newfont.nospellcheck_, nospellcheck_));
388 if (newfont.color_ == color_ && toggleall)
389 setColor(Color_inherit); // toggle 'back'
390 else if (newfont.color_ != Color_ignore)
391 setColor(newfont.color_);
393 if (newfont.background_ == background_ && toggleall)
394 setBackground(Color_inherit); // toggle 'back'
395 else if (newfont.background_ != Color_ignore)
396 setBackground(newfont.background_);
399 /// Is font resolved?
400 bool FontInfo::resolved() const
402 return (family_ != INHERIT_FAMILY && series_ != INHERIT_SERIES
403 && shape_ != INHERIT_SHAPE && size_ != FONT_SIZE_INHERIT
404 && emph_ != FONT_INHERIT && underbar_ != FONT_INHERIT
405 && uuline_ != FONT_INHERIT && uwave_ != FONT_INHERIT
406 && strikeout_ != FONT_INHERIT && xout_ != FONT_INHERIT
407 && noun_ != FONT_INHERIT && color_ != Color_inherit
408 && background_ != Color_inherit && nospellcheck_ != FONT_INHERIT);
412 Color FontInfo::realColor() const
414 if (paint_color_ != Color_none)
416 if (color_ == Color_none)
417 return Color_foreground;
424 void appendSep(string & s1, string const & s2)
428 s1 += s1.empty() ? "" : "\n";
433 string makeCSSTag(string const & key, string const & val)
435 return key + ": " + val + ";";
439 string getFamilyCSS(FontFamily const & f)
446 case TYPEWRITER_FAMILY:
468 string getSeriesCSS(FontSeries const & s)
483 string getShapeCSS(FontShape const & s)
485 string fs = "normal";
486 string fv = "normal";
488 case UP_SHAPE: break;
489 case ITALIC_SHAPE: fs = "italic"; break;
490 case SLANTED_SHAPE: fs = "oblique"; break;
491 case SMALLCAPS_SHAPE: fv = "small-caps"; break;
494 fs = ""; fv = ""; break;
498 appendSep(retval, makeCSSTag("font-style", fs));
500 appendSep(retval, makeCSSTag("font-variant", fv));
505 string getSizeCSS(FontSize const & s)
510 case FONT_SIZE_SCRIPT:
512 case FONT_SIZE_FOOTNOTE:
513 case FONT_SIZE_SMALL:
515 case FONT_SIZE_NORMAL:
517 case FONT_SIZE_LARGE:
519 case FONT_SIZE_LARGER:
520 case FONT_SIZE_LARGEST:
523 case FONT_SIZE_HUGER:
525 case FONT_SIZE_INCREASE:
527 case FONT_SIZE_DECREASE:
529 case FONT_SIZE_IGNORE:
530 case FONT_SIZE_INHERIT:
539 // FIXME This does not yet handle color
540 docstring FontInfo::asCSS() const
543 string tmp = getFamilyCSS(family_);
545 appendSep(retval, makeCSSTag("font-family", tmp));
546 tmp = getSeriesCSS(series_);
548 appendSep(retval, makeCSSTag("font-weight", tmp));
549 appendSep(retval, getShapeCSS(shape_));
550 tmp = getSizeCSS(size_);
552 appendSep(retval, makeCSSTag("font-size", tmp));
553 return from_ascii(retval);
557 // Set family according to lyx format string
558 void setLyXFamily(string const & fam, FontInfo & f)
560 string const s = ascii_lowercase(fam);
563 while (LyXFamilyNames[i] != s &&
564 LyXFamilyNames[i] != string("error"))
566 if (s == LyXFamilyNames[i])
567 f.setFamily(FontFamily(i));
569 LYXERR0("Unknown family `" << s << '\'');
573 // Set series according to lyx format string
574 void setLyXSeries(string const & ser, FontInfo & f)
576 string const s = ascii_lowercase(ser);
579 while (LyXSeriesNames[i] != s &&
580 LyXSeriesNames[i] != string("error")) ++i;
581 if (s == LyXSeriesNames[i]) {
582 f.setSeries(FontSeries(i));
584 LYXERR0("Unknown series `" << s << '\'');
588 // Set shape according to lyx format string
589 void setLyXShape(string const & sha, FontInfo & f)
591 string const s = ascii_lowercase(sha);
594 while (LyXShapeNames[i] != s && LyXShapeNames[i] != string("error"))
596 if (s == LyXShapeNames[i])
597 f.setShape(FontShape(i));
599 LYXERR0("Unknown shape `" << s << '\'');
603 // Set size according to lyx format string
604 void setLyXSize(string const & siz, FontInfo & f)
606 string const s = ascii_lowercase(siz);
608 while (LyXSizeNames[i] != s && LyXSizeNames[i] != string("error"))
610 if (s == LyXSizeNames[i]) {
611 f.setSize(FontSize(i));
613 LYXERR0("Unknown size `" << s << '\'');
617 // Set size according to lyx format string
618 FontState setLyXMisc(string const & siz)
620 string const s = ascii_lowercase(siz);
622 while (LyXMiscNames[i] != s &&
623 LyXMiscNames[i] != string("error")) ++i;
624 if (s == LyXMiscNames[i])
626 LYXERR0("Unknown misc flag `" << s << '\'');
631 /// Sets color after LyX text format
632 void setLyXColor(string const & col, FontInfo & f)
634 f.setColor(lcolor.getFromLyXName(col));
638 // Read a font definition from given file in lyx format
640 FontInfo lyxRead(Lexer & lex, FontInfo const & fi)
644 bool finished = false;
645 while (!finished && lex.isOK() && !error) {
647 string const tok = ascii_lowercase(lex.getString());
651 } else if (tok == "endfont") {
653 } else if (tok == "family") {
655 string const ttok = lex.getString();
656 setLyXFamily(ttok, f);
657 } else if (tok == "series") {
659 string const ttok = lex.getString();
660 setLyXSeries(ttok, f);
661 } else if (tok == "shape") {
663 string const ttok = lex.getString();
664 setLyXShape(ttok, f);
665 } else if (tok == "size") {
667 string const ttok = lex.getString();
669 } else if (tok == "misc") {
671 string const ttok = ascii_lowercase(lex.getString());
673 if (ttok == "no_bar") {
674 f.setUnderbar(FONT_OFF);
675 } else if (ttok == "no_strikeout") {
676 f.setStrikeout(FONT_OFF);
677 } else if (ttok == "no_xout") {
679 } else if (ttok == "no_uuline") {
680 f.setUuline(FONT_OFF);
681 } else if (ttok == "no_uwave") {
682 f.setUwave(FONT_OFF);
683 } else if (ttok == "no_emph") {
685 } else if (ttok == "no_noun") {
687 } else if (ttok == "emph") {
689 } else if (ttok == "underbar") {
690 f.setUnderbar(FONT_ON);
691 } else if (ttok == "strikeout") {
692 f.setStrikeout(FONT_ON);
693 } else if (ttok == "xout") {
695 } else if (ttok == "uuline") {
696 f.setUuline(FONT_ON);
697 } else if (ttok == "uwave") {
699 } else if (ttok == "noun") {
701 } else if (ttok == "nospellcheck") {
702 f.setNoSpellcheck(FONT_ON);
703 } else if (ttok == "no_nospellcheck") {
704 f.setNoSpellcheck(FONT_OFF);
706 lex.printError("Illegal misc type");
708 } else if (tok == "color") {
710 string const ttok = lex.getString();
711 setLyXColor(ttok, f);
713 lex.printError("Unknown tag");
721 void lyxWrite(ostream & os, FontInfo const & f, string const & start, int level)
724 for (int i = 0; i < level; ++i)
727 if (f.family() != INHERIT_FAMILY)
728 oss << indent << "\tFamily " << LyXFamilyNames[f.family()]
730 if (f.series() != INHERIT_SERIES)
731 oss << indent << "\tSeries " << LyXSeriesNames[f.series()]
733 if (f.shape() != INHERIT_SHAPE)
734 oss << indent << "\tShape " << LyXShapeNames[f.shape()]
736 if (f.size() != FONT_SIZE_INHERIT)
737 oss << indent << "\tSize " << LyXSizeNames[f.size()]
739 if (f.underbar() == FONT_ON)
740 oss << indent << "\tMisc Underbar\n";
741 else if (f.underbar() == FONT_OFF)
742 oss << indent << "\tMisc No_Bar\n";
743 if (f.strikeout() == FONT_ON)
744 oss << indent << "\tMisc Strikeout\n";
745 else if (f.strikeout() == FONT_OFF)
746 oss << indent << "\tMisc No_Strikeout\n";
747 if (f.xout() == FONT_ON)
748 oss << indent << "\tMisc Xout\n";
749 else if (f.xout() == FONT_OFF)
750 oss << indent << "\tMisc No_Xout\n";
751 if (f.uuline() == FONT_ON)
752 oss << indent << "\tMisc Uuline\n";
753 else if (f.uuline() == FONT_OFF)
754 oss << indent << "\tMisc No_Uuline\n";
755 if (f.uwave() == FONT_ON)
756 oss << indent << "\tMisc Uwave\n";
757 else if (f.uwave() == FONT_OFF)
758 oss << indent << "\tMisc No_Uwave\n";
759 if (f.emph() == FONT_ON)
760 oss << indent << "\tMisc Emph\n";
761 else if (f.emph() == FONT_OFF)
762 oss << indent << "\tMisc No_Emph\n";
763 if (f.noun() == FONT_ON)
764 oss << indent << "\tMisc Noun\n";
765 else if (f.noun() == FONT_OFF)
766 oss << indent << "\tMisc No_Noun\n";
767 if (f.nospellcheck() == FONT_ON)
768 oss << indent << "\tMisc NoSpellcheck\n";
769 else if (f.nospellcheck() == FONT_OFF)
770 oss << indent << "\tMisc No_NoSpellcheck\n";
771 if (f.color() != Color_inherit && f.color() != Color_none)
772 oss << indent << "\tColor " << lcolor.getLyXName(f.color())
774 if (!oss.str().empty()) {
775 os << indent << start << '\n'
777 << indent << "EndFont\n";