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", "ds", "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(
76 FontInfo const inherit_font(
92 FontInfo const ignore_font(
115 /// Decreases font size_ by one
116 FontInfo & FontInfo::decSize()
119 case FONT_SIZE_HUGER: size_ = FONT_SIZE_HUGE; break;
120 case FONT_SIZE_HUGE: size_ = FONT_SIZE_LARGEST; break;
121 case FONT_SIZE_LARGEST: size_ = FONT_SIZE_LARGER; break;
122 case FONT_SIZE_LARGER: size_ = FONT_SIZE_LARGE; break;
123 case FONT_SIZE_LARGE: size_ = FONT_SIZE_NORMAL; break;
124 case FONT_SIZE_NORMAL: size_ = FONT_SIZE_SMALL; break;
125 case FONT_SIZE_SMALL: size_ = FONT_SIZE_FOOTNOTE; break;
126 case FONT_SIZE_FOOTNOTE: size_ = FONT_SIZE_SCRIPT; break;
127 case FONT_SIZE_SCRIPT: size_ = FONT_SIZE_TINY; break;
128 case FONT_SIZE_TINY: break;
129 case FONT_SIZE_INCREASE:
130 LYXERR0("Can't FontInfo::decSize on FONT_SIZE_INCREASE");
132 case FONT_SIZE_DECREASE:
133 LYXERR0("Can't FontInfo::decSize on FONT_SIZE_DECREASE");
135 case FONT_SIZE_INHERIT:
136 LYXERR0("Can't FontInfo::decSize on FONT_SIZE_INHERIT");
138 case FONT_SIZE_IGNORE:
139 LYXERR0("Can't FontInfo::decSize on FONT_SIZE_IGNORE");
146 /// Increases font size_ by one
147 FontInfo & FontInfo::incSize()
150 case FONT_SIZE_HUGER: break;
151 case FONT_SIZE_HUGE: size_ = FONT_SIZE_HUGER; break;
152 case FONT_SIZE_LARGEST: size_ = FONT_SIZE_HUGE; break;
153 case FONT_SIZE_LARGER: size_ = FONT_SIZE_LARGEST; break;
154 case FONT_SIZE_LARGE: size_ = FONT_SIZE_LARGER; break;
155 case FONT_SIZE_NORMAL: size_ = FONT_SIZE_LARGE; break;
156 case FONT_SIZE_SMALL: size_ = FONT_SIZE_NORMAL; break;
157 case FONT_SIZE_FOOTNOTE: size_ = FONT_SIZE_SMALL; break;
158 case FONT_SIZE_SCRIPT: size_ = FONT_SIZE_FOOTNOTE; break;
159 case FONT_SIZE_TINY: size_ = FONT_SIZE_SCRIPT; break;
160 case FONT_SIZE_INCREASE:
161 LYXERR0("Can't FontInfo::incSize on FONT_SIZE_INCREASE");
163 case FONT_SIZE_DECREASE:
164 LYXERR0("Can't FontInfo::incSize on FONT_SIZE_DECREASE");
166 case FONT_SIZE_INHERIT:
167 LYXERR0("Can't FontInfo::incSize on FONT_SIZE_INHERIT");
169 case FONT_SIZE_IGNORE:
170 LYXERR0("Can't FontInfo::incSize on FONT_SIZE_IGNORE");
177 double FontInfo::realSize() const
179 double d = convert<double>(lyxrc.font_sizes[size()]);
180 // The following is according to the average of the values in the
181 // definitions of \defaultscriptratio and \defaultscriptscriptratio in LaTeX
182 // font packages. No attempt is made to implement the actual values from
191 case LM_ST_SCRIPTSCRIPT:
195 // Never go below the smallest size
196 return max(d, convert<double>(lyxrc.font_sizes[FONT_SIZE_TINY]));
200 /// Reduce font to fall back to template where possible
201 void FontInfo::reduce(FontInfo const & tmplt)
203 if (family_ == tmplt.family_)
204 family_ = INHERIT_FAMILY;
205 if (series_ == tmplt.series_)
206 series_ = INHERIT_SERIES;
207 if (shape_ == tmplt.shape_)
208 shape_ = INHERIT_SHAPE;
209 if (size_ == tmplt.size_)
210 size_ = FONT_SIZE_INHERIT;
211 if (emph_ == tmplt.emph_)
212 emph_ = FONT_INHERIT;
213 if (underbar_ == tmplt.underbar_)
214 underbar_ = FONT_INHERIT;
215 if (strikeout_ == tmplt.strikeout_)
216 strikeout_ = FONT_INHERIT;
217 if (xout_ == tmplt.xout_)
218 xout_ = FONT_INHERIT;
219 if (uuline_ == tmplt.uuline_)
220 uuline_ = FONT_INHERIT;
221 if (uwave_ == tmplt.uwave_)
222 uwave_ = FONT_INHERIT;
223 if (noun_ == tmplt.noun_)
224 noun_ = FONT_INHERIT;
225 if (color_ == tmplt.color_)
226 color_ = Color_inherit;
227 if (background_ == tmplt.background_)
228 background_ = Color_inherit;
232 /// Realize font from a template
233 FontInfo & FontInfo::realize(FontInfo const & tmplt)
235 if ((*this) == inherit_font) {
240 if (family_ == INHERIT_FAMILY)
241 family_ = tmplt.family_;
243 if (series_ == INHERIT_SERIES)
244 series_ = tmplt.series_;
246 if (shape_ == INHERIT_SHAPE)
247 shape_ = tmplt.shape_;
249 if (size_ == FONT_SIZE_INHERIT)
252 if (emph_ == FONT_INHERIT)
255 if (underbar_ == FONT_INHERIT)
256 underbar_ = tmplt.underbar_;
258 if (strikeout_ == FONT_INHERIT)
259 strikeout_ = tmplt.strikeout_;
261 if (xout_ == FONT_INHERIT)
264 if (uuline_ == FONT_INHERIT)
265 uuline_ = tmplt.uuline_;
267 if (uwave_ == FONT_INHERIT)
268 uwave_ = tmplt.uwave_;
270 if (noun_ == FONT_INHERIT)
273 if (color_ == Color_inherit)
274 color_ = tmplt.color_;
276 if (background_ == Color_inherit)
277 background_ = tmplt.background_;
283 Changer FontInfo::changeColor(ColorCode const color)
285 return make_change(color_, color);
289 Changer FontInfo::changeShape(FontShape const shape)
291 return make_change(shape_, shape);
295 Changer FontInfo::changeStyle(MathStyle const new_style)
297 return make_change(style_, new_style);
301 Changer FontInfo::change(FontInfo font, bool realiz)
305 return make_change(*this, font);
309 /// Updates a misc setting according to request
310 static FontState setMisc(FontState newfont,
313 if (newfont == FONT_TOGGLE) {
316 else if (org == FONT_OFF)
319 LYXERR0("Font::setMisc: Need state"
320 " FONT_ON or FONT_OFF to toggle. Setting to FONT_ON");
323 } else if (newfont == FONT_IGNORE)
329 /// Updates font settings according to request
330 void FontInfo::update(FontInfo const & newfont, bool toggleall)
332 if (newfont.family_ == family_ && toggleall)
333 setFamily(INHERIT_FAMILY); // toggle 'back'
334 else if (newfont.family_ != IGNORE_FAMILY)
335 setFamily(newfont.family_);
336 // else it's IGNORE_SHAPE
338 // "Old" behaviour: "Setting" bold will toggle bold on/off.
339 switch (newfont.series_) {
342 if (series_ == BOLD_SERIES && toggleall)
343 setSeries(MEDIUM_SERIES);
345 setSeries(BOLD_SERIES);
349 setSeries(newfont.series_);
355 if (newfont.shape_ == shape_ && toggleall)
356 shape_ = INHERIT_SHAPE; // toggle 'back'
357 else if (newfont.shape_ != IGNORE_SHAPE)
358 shape_ = newfont.shape_;
359 // else it's IGNORE_SHAPE
361 if (newfont.size_ != FONT_SIZE_IGNORE) {
362 if (newfont.size_ == FONT_SIZE_INCREASE)
364 else if (newfont.size_ == FONT_SIZE_DECREASE)
367 size_ = newfont.size_;
370 setEmph(setMisc(newfont.emph_, emph_));
371 setUnderbar(setMisc(newfont.underbar_, underbar_));
372 setStrikeout(setMisc(newfont.strikeout_, strikeout_));
373 setXout(setMisc(newfont.xout_, xout_));
374 setUuline(setMisc(newfont.uuline_, uuline_));
375 setUwave(setMisc(newfont.uwave_, uwave_));
376 setNoun(setMisc(newfont.noun_, noun_));
377 setNumber(setMisc(newfont.number_, number_));
379 if (newfont.color_ == color_ && toggleall)
380 setColor(Color_inherit); // toggle 'back'
381 else if (newfont.color_ != Color_ignore)
382 setColor(newfont.color_);
384 if (newfont.background_ == background_ && toggleall)
385 setBackground(Color_inherit); // toggle 'back'
386 else if (newfont.background_ != Color_ignore)
387 setBackground(newfont.background_);
390 /// Is font resolved?
391 bool FontInfo::resolved() const
393 return (family_ != INHERIT_FAMILY && series_ != INHERIT_SERIES
394 && shape_ != INHERIT_SHAPE && size_ != FONT_SIZE_INHERIT
395 && emph_ != FONT_INHERIT && underbar_ != FONT_INHERIT
396 && uuline_ != FONT_INHERIT && uwave_ != FONT_INHERIT
397 && strikeout_ != FONT_INHERIT && xout_ != FONT_INHERIT
398 && noun_ != FONT_INHERIT && color_ != Color_inherit
399 && background_ != Color_inherit);
403 Color FontInfo::realColor() const
405 if (paint_color_ != Color_none)
407 if (color_ == Color_none)
408 return Color_foreground;
415 void appendSep(string & s1, string const & s2)
419 s1 += s1.empty() ? "" : "\n";
424 string makeCSSTag(string const & key, string const & val)
426 return key + ": " + val + ";";
430 string getFamilyCSS(FontFamily const & f)
437 case TYPEWRITER_FAMILY:
460 string getSeriesCSS(FontSeries const & s)
475 string getShapeCSS(FontShape const & s)
477 string fs = "normal";
478 string fv = "normal";
480 case UP_SHAPE: break;
481 case ITALIC_SHAPE: fs = "italic"; break;
482 case SLANTED_SHAPE: fs = "oblique"; break;
483 case SMALLCAPS_SHAPE: fv = "small-caps"; break;
486 fs = ""; fv = ""; break;
490 appendSep(retval, makeCSSTag("font-style", fs));
492 appendSep(retval, makeCSSTag("font-variant", fv));
497 string getSizeCSS(FontSize const & s)
502 case FONT_SIZE_SCRIPT:
504 case FONT_SIZE_FOOTNOTE:
505 case FONT_SIZE_SMALL:
507 case FONT_SIZE_NORMAL:
509 case FONT_SIZE_LARGE:
511 case FONT_SIZE_LARGER:
512 case FONT_SIZE_LARGEST:
515 case FONT_SIZE_HUGER:
517 case FONT_SIZE_INCREASE:
519 case FONT_SIZE_DECREASE:
521 case FONT_SIZE_IGNORE:
522 case FONT_SIZE_INHERIT:
531 // FIXME This does not yet handle color
532 docstring FontInfo::asCSS() const
535 string tmp = getFamilyCSS(family_);
537 appendSep(retval, makeCSSTag("font-family", tmp));
538 tmp = getSeriesCSS(series_);
540 appendSep(retval, makeCSSTag("font-weight", tmp));
541 appendSep(retval, getShapeCSS(shape_));
542 tmp = getSizeCSS(size_);
544 appendSep(retval, makeCSSTag("font-size", tmp));
545 return from_ascii(retval);
549 // Set family according to lyx format string
550 void setLyXFamily(string const & fam, FontInfo & f)
552 string const s = ascii_lowercase(fam);
555 while (LyXFamilyNames[i] != s &&
556 LyXFamilyNames[i] != string("error"))
558 if (s == LyXFamilyNames[i])
559 f.setFamily(FontFamily(i));
561 LYXERR0("Unknown family `" << s << '\'');
565 // Set series according to lyx format string
566 void setLyXSeries(string const & ser, FontInfo & f)
568 string const s = ascii_lowercase(ser);
571 while (LyXSeriesNames[i] != s &&
572 LyXSeriesNames[i] != string("error")) ++i;
573 if (s == LyXSeriesNames[i]) {
574 f.setSeries(FontSeries(i));
576 LYXERR0("Unknown series `" << s << '\'');
580 // Set shape according to lyx format string
581 void setLyXShape(string const & sha, FontInfo & f)
583 string const s = ascii_lowercase(sha);
586 while (LyXShapeNames[i] != s && LyXShapeNames[i] != string("error"))
588 if (s == LyXShapeNames[i])
589 f.setShape(FontShape(i));
591 LYXERR0("Unknown shape `" << s << '\'');
595 // Set size according to lyx format string
596 void setLyXSize(string const & siz, FontInfo & f)
598 string const s = ascii_lowercase(siz);
600 while (LyXSizeNames[i] != s && LyXSizeNames[i] != string("error"))
602 if (s == LyXSizeNames[i]) {
603 f.setSize(FontSize(i));
605 LYXERR0("Unknown size `" << s << '\'');
609 // Set size according to lyx format string
610 FontState setLyXMisc(string const & siz)
612 string const s = ascii_lowercase(siz);
614 while (LyXMiscNames[i] != s &&
615 LyXMiscNames[i] != string("error")) ++i;
616 if (s == LyXMiscNames[i])
618 LYXERR0("Unknown misc flag `" << s << '\'');
623 /// Sets color after LyX text format
624 void setLyXColor(string const & col, FontInfo & f)
626 f.setColor(lcolor.getFromLyXName(col));
630 // Read a font definition from given file in lyx format
632 FontInfo lyxRead(Lexer & lex, FontInfo const & fi)
636 bool finished = false;
637 while (!finished && lex.isOK() && !error) {
639 string const tok = ascii_lowercase(lex.getString());
643 } else if (tok == "endfont") {
645 } else if (tok == "family") {
647 string const ttok = lex.getString();
648 setLyXFamily(ttok, f);
649 } else if (tok == "series") {
651 string const ttok = lex.getString();
652 setLyXSeries(ttok, f);
653 } else if (tok == "shape") {
655 string const ttok = lex.getString();
656 setLyXShape(ttok, f);
657 } else if (tok == "size") {
659 string const ttok = lex.getString();
661 } else if (tok == "misc") {
663 string const ttok = ascii_lowercase(lex.getString());
665 if (ttok == "no_bar") {
666 f.setUnderbar(FONT_OFF);
667 } else if (ttok == "no_strikeout") {
668 f.setStrikeout(FONT_OFF);
669 } else if (ttok == "no_xout") {
671 } else if (ttok == "no_uuline") {
672 f.setUuline(FONT_OFF);
673 } else if (ttok == "no_uwave") {
674 f.setUwave(FONT_OFF);
675 } else if (ttok == "no_emph") {
677 } else if (ttok == "no_noun") {
679 } else if (ttok == "emph") {
681 } else if (ttok == "underbar") {
682 f.setUnderbar(FONT_ON);
683 } else if (ttok == "strikeout") {
684 f.setStrikeout(FONT_ON);
685 } else if (ttok == "xout") {
687 } else if (ttok == "uuline") {
688 f.setUuline(FONT_ON);
689 } else if (ttok == "uwave") {
691 } else if (ttok == "noun") {
694 lex.printError("Illegal misc type");
696 } else if (tok == "color") {
698 string const ttok = lex.getString();
699 setLyXColor(ttok, f);
701 lex.printError("Unknown tag");
709 void lyxWrite(ostream & os, FontInfo const & f, string const & start, int level)
712 for (int i = 0; i < level; ++i)
715 if (f.family() != INHERIT_FAMILY)
716 oss << indent << "\tFamily " << LyXFamilyNames[f.family()]
718 if (f.series() != INHERIT_SERIES)
719 oss << indent << "\tSeries " << LyXSeriesNames[f.series()]
721 if (f.shape() != INHERIT_SHAPE)
722 oss << indent << "\tShape " << LyXShapeNames[f.shape()]
724 if (f.size() != FONT_SIZE_INHERIT)
725 oss << indent << "\tSize " << LyXSizeNames[f.size()]
727 if (f.underbar() == FONT_ON)
728 oss << indent << "\tMisc Underbar\n";
729 else if (f.underbar() == FONT_OFF)
730 oss << indent << "\tMisc No_Bar\n";
731 if (f.strikeout() == FONT_ON)
732 oss << indent << "\tMisc Strikeout\n";
733 else if (f.strikeout() == FONT_OFF)
734 oss << indent << "\tMisc No_Strikeout\n";
735 if (f.xout() == FONT_ON)
736 oss << indent << "\tMisc Xout\n";
737 else if (f.xout() == FONT_OFF)
738 oss << indent << "\tMisc No_Xout\n";
739 if (f.uuline() == FONT_ON)
740 oss << indent << "\tMisc Uuline\n";
741 else if (f.uuline() == FONT_OFF)
742 oss << indent << "\tMisc No_Uuline\n";
743 if (f.uwave() == FONT_ON)
744 oss << indent << "\tMisc Uwave\n";
745 else if (f.uwave() == FONT_OFF)
746 oss << indent << "\tMisc No_Uwave\n";
747 if (f.emph() == FONT_ON)
748 oss << indent << "\tMisc Emph\n";
749 else if (f.emph() == FONT_OFF)
750 oss << indent << "\tMisc No_Emph\n";
751 if (f.noun() == FONT_ON)
752 oss << indent << "\tMisc Noun\n";
753 else if (f.noun() == FONT_OFF)
754 oss << indent << "\tMisc No_Noun\n";
755 if (f.color() != Color_inherit && f.color() != Color_none)
756 oss << indent << "\tColor " << lcolor.getLyXName(f.color())
758 if (!oss.str().empty()) {
759 os << indent << start << '\n'
761 << indent << "EndFont\n";