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(
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:
459 string getSeriesCSS(FontSeries const & s)
474 string getShapeCSS(FontShape const & s)
476 string fs = "normal";
477 string fv = "normal";
479 case UP_SHAPE: break;
480 case ITALIC_SHAPE: fs = "italic"; break;
481 case SLANTED_SHAPE: fs = "oblique"; break;
482 case SMALLCAPS_SHAPE: fv = "small-caps"; break;
485 fs = ""; fv = ""; break;
489 appendSep(retval, makeCSSTag("font-style", fs));
491 appendSep(retval, makeCSSTag("font-variant", fv));
496 string getSizeCSS(FontSize const & s)
501 case FONT_SIZE_SCRIPT:
503 case FONT_SIZE_FOOTNOTE:
504 case FONT_SIZE_SMALL:
506 case FONT_SIZE_NORMAL:
508 case FONT_SIZE_LARGE:
510 case FONT_SIZE_LARGER:
511 case FONT_SIZE_LARGEST:
514 case FONT_SIZE_HUGER:
516 case FONT_SIZE_INCREASE:
518 case FONT_SIZE_DECREASE:
520 case FONT_SIZE_IGNORE:
521 case FONT_SIZE_INHERIT:
530 // FIXME This does not yet handle color
531 docstring FontInfo::asCSS() const
534 string tmp = getFamilyCSS(family_);
536 appendSep(retval, makeCSSTag("font-family", tmp));
537 tmp = getSeriesCSS(series_);
539 appendSep(retval, makeCSSTag("font-weight", tmp));
540 appendSep(retval, getShapeCSS(shape_));
541 tmp = getSizeCSS(size_);
543 appendSep(retval, makeCSSTag("font-size", tmp));
544 return from_ascii(retval);
548 // Set family according to lyx format string
549 void setLyXFamily(string const & fam, FontInfo & f)
551 string const s = ascii_lowercase(fam);
554 while (LyXFamilyNames[i] != s &&
555 LyXFamilyNames[i] != string("error"))
557 if (s == LyXFamilyNames[i])
558 f.setFamily(FontFamily(i));
560 LYXERR0("Unknown family `" << s << '\'');
564 // Set series according to lyx format string
565 void setLyXSeries(string const & ser, FontInfo & f)
567 string const s = ascii_lowercase(ser);
570 while (LyXSeriesNames[i] != s &&
571 LyXSeriesNames[i] != string("error")) ++i;
572 if (s == LyXSeriesNames[i]) {
573 f.setSeries(FontSeries(i));
575 LYXERR0("Unknown series `" << s << '\'');
579 // Set shape according to lyx format string
580 void setLyXShape(string const & sha, FontInfo & f)
582 string const s = ascii_lowercase(sha);
585 while (LyXShapeNames[i] != s && LyXShapeNames[i] != string("error"))
587 if (s == LyXShapeNames[i])
588 f.setShape(FontShape(i));
590 LYXERR0("Unknown shape `" << s << '\'');
594 // Set size according to lyx format string
595 void setLyXSize(string const & siz, FontInfo & f)
597 string const s = ascii_lowercase(siz);
599 while (LyXSizeNames[i] != s && LyXSizeNames[i] != string("error"))
601 if (s == LyXSizeNames[i]) {
602 f.setSize(FontSize(i));
604 LYXERR0("Unknown size `" << s << '\'');
608 // Set size according to lyx format string
609 FontState setLyXMisc(string const & siz)
611 string const s = ascii_lowercase(siz);
613 while (LyXMiscNames[i] != s &&
614 LyXMiscNames[i] != string("error")) ++i;
615 if (s == LyXMiscNames[i])
617 LYXERR0("Unknown misc flag `" << s << '\'');
622 /// Sets color after LyX text format
623 void setLyXColor(string const & col, FontInfo & f)
625 f.setColor(lcolor.getFromLyXName(col));
629 // Read a font definition from given file in lyx format
631 FontInfo lyxRead(Lexer & lex, FontInfo const & fi)
635 bool finished = false;
636 while (!finished && lex.isOK() && !error) {
638 string const tok = ascii_lowercase(lex.getString());
642 } else if (tok == "endfont") {
644 } else if (tok == "family") {
646 string const ttok = lex.getString();
647 setLyXFamily(ttok, f);
648 } else if (tok == "series") {
650 string const ttok = lex.getString();
651 setLyXSeries(ttok, f);
652 } else if (tok == "shape") {
654 string const ttok = lex.getString();
655 setLyXShape(ttok, f);
656 } else if (tok == "size") {
658 string const ttok = lex.getString();
660 } else if (tok == "misc") {
662 string const ttok = ascii_lowercase(lex.getString());
664 if (ttok == "no_bar") {
665 f.setUnderbar(FONT_OFF);
666 } else if (ttok == "no_strikeout") {
667 f.setStrikeout(FONT_OFF);
668 } else if (ttok == "no_xout") {
670 } else if (ttok == "no_uuline") {
671 f.setUuline(FONT_OFF);
672 } else if (ttok == "no_uwave") {
673 f.setUwave(FONT_OFF);
674 } else if (ttok == "no_emph") {
676 } else if (ttok == "no_noun") {
678 } else if (ttok == "emph") {
680 } else if (ttok == "underbar") {
681 f.setUnderbar(FONT_ON);
682 } else if (ttok == "strikeout") {
683 f.setStrikeout(FONT_ON);
684 } else if (ttok == "xout") {
686 } else if (ttok == "uuline") {
687 f.setUuline(FONT_ON);
688 } else if (ttok == "uwave") {
690 } else if (ttok == "noun") {
693 lex.printError("Illegal misc type");
695 } else if (tok == "color") {
697 string const ttok = lex.getString();
698 setLyXColor(ttok, f);
700 lex.printError("Unknown tag");
708 void lyxWrite(ostream & os, FontInfo const & f, string const & start, int level)
711 for (int i = 0; i < level; ++i)
714 if (f.family() != INHERIT_FAMILY)
715 oss << indent << "\tFamily " << LyXFamilyNames[f.family()]
717 if (f.series() != INHERIT_SERIES)
718 oss << indent << "\tSeries " << LyXSeriesNames[f.series()]
720 if (f.shape() != INHERIT_SHAPE)
721 oss << indent << "\tShape " << LyXShapeNames[f.shape()]
723 if (f.size() != FONT_SIZE_INHERIT)
724 oss << indent << "\tSize " << LyXSizeNames[f.size()]
726 if (f.underbar() == FONT_ON)
727 oss << indent << "\tMisc Underbar\n";
728 else if (f.underbar() == FONT_OFF)
729 oss << indent << "\tMisc No_Bar\n";
730 if (f.strikeout() == FONT_ON)
731 oss << indent << "\tMisc Strikeout\n";
732 else if (f.strikeout() == FONT_OFF)
733 oss << indent << "\tMisc No_Strikeout\n";
734 if (f.xout() == FONT_ON)
735 oss << indent << "\tMisc Xout\n";
736 else if (f.xout() == FONT_OFF)
737 oss << indent << "\tMisc No_Xout\n";
738 if (f.uuline() == FONT_ON)
739 oss << indent << "\tMisc Uuline\n";
740 else if (f.uuline() == FONT_OFF)
741 oss << indent << "\tMisc No_Uuline\n";
742 if (f.uwave() == FONT_ON)
743 oss << indent << "\tMisc Uwave\n";
744 else if (f.uwave() == FONT_OFF)
745 oss << indent << "\tMisc No_Uwave\n";
746 if (f.emph() == FONT_ON)
747 oss << indent << "\tMisc Emph\n";
748 else if (f.emph() == FONT_OFF)
749 oss << indent << "\tMisc No_Emph\n";
750 if (f.noun() == FONT_ON)
751 oss << indent << "\tMisc Noun\n";
752 else if (f.noun() == FONT_OFF)
753 oss << indent << "\tMisc No_Noun\n";
754 if (f.color() != Color_inherit && f.color() != Color_none)
755 oss << indent << "\tColor " << lcolor.getLyXName(f.color())
757 if (!oss.str().empty()) {
758 os << indent << start << '\n'
760 << indent << "EndFont\n";