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.
21 #include "support/debug.h"
22 #include "support/docstring.h"
23 #include "support/lstrings.h"
24 #include "support/RefChanger.h"
30 using namespace lyx::support;
35 // Strings used to read and write .lyx format files
37 char const * LyXFamilyNames[NUM_FAMILIES + 2 /* default & error */] =
38 { "roman", "sans", "typewriter", "symbol",
39 "cmr", "cmsy", "cmm", "cmex", "msa", "msb", "eufrak", "rsfs", "stmry",
40 "wasy", "esint", "default", "error" };
42 char const * LyXSeriesNames[NUM_SERIES + 2 /* default & error */] =
43 { "medium", "bold", "default", "error" };
45 char const * LyXShapeNames[NUM_SHAPE + 2 /* default & error */] =
46 { "up", "italic", "slanted", "smallcaps", "default", "error" };
48 char const * LyXSizeNames[NUM_SIZE + 4 /* increase, decrease, default & error */] =
49 { "tiny", "scriptsize", "footnotesize", "small", "normal", "large",
50 "larger", "largest", "huge", "giant",
51 "increase", "decrease", "default", "error" };
53 char const * LyXMiscNames[5] =
54 { "off", "on", "toggle", "default", "error" };
57 FontInfo const sane_font(
72 FontInfo const inherit_font(
87 FontInfo const ignore_font(
109 /// Decreases font size_ by one
110 FontInfo & FontInfo::decSize()
113 case FONT_SIZE_HUGER: size_ = FONT_SIZE_HUGE; break;
114 case FONT_SIZE_HUGE: size_ = FONT_SIZE_LARGEST; break;
115 case FONT_SIZE_LARGEST: size_ = FONT_SIZE_LARGER; break;
116 case FONT_SIZE_LARGER: size_ = FONT_SIZE_LARGE; break;
117 case FONT_SIZE_LARGE: size_ = FONT_SIZE_NORMAL; break;
118 case FONT_SIZE_NORMAL: size_ = FONT_SIZE_SMALL; break;
119 case FONT_SIZE_SMALL: size_ = FONT_SIZE_FOOTNOTE; break;
120 case FONT_SIZE_FOOTNOTE: size_ = FONT_SIZE_SCRIPT; break;
121 case FONT_SIZE_SCRIPT: size_ = FONT_SIZE_TINY; break;
122 case FONT_SIZE_TINY: break;
123 case FONT_SIZE_INCREASE:
124 LYXERR0("Can't FontInfo::decSize on FONT_SIZE_INCREASE");
126 case FONT_SIZE_DECREASE:
127 LYXERR0("Can't FontInfo::decSize on FONT_SIZE_DECREASE");
129 case FONT_SIZE_INHERIT:
130 LYXERR0("Can't FontInfo::decSize on FONT_SIZE_INHERIT");
132 case FONT_SIZE_IGNORE:
133 LYXERR0("Can't FontInfo::decSize on FONT_SIZE_IGNORE");
140 /// Increases font size_ by one
141 FontInfo & FontInfo::incSize()
144 case FONT_SIZE_HUGER: break;
145 case FONT_SIZE_HUGE: size_ = FONT_SIZE_HUGER; break;
146 case FONT_SIZE_LARGEST: size_ = FONT_SIZE_HUGE; break;
147 case FONT_SIZE_LARGER: size_ = FONT_SIZE_LARGEST; break;
148 case FONT_SIZE_LARGE: size_ = FONT_SIZE_LARGER; break;
149 case FONT_SIZE_NORMAL: size_ = FONT_SIZE_LARGE; break;
150 case FONT_SIZE_SMALL: size_ = FONT_SIZE_NORMAL; break;
151 case FONT_SIZE_FOOTNOTE: size_ = FONT_SIZE_SMALL; break;
152 case FONT_SIZE_SCRIPT: size_ = FONT_SIZE_FOOTNOTE; break;
153 case FONT_SIZE_TINY: size_ = FONT_SIZE_SCRIPT; break;
154 case FONT_SIZE_INCREASE:
155 LYXERR0("Can't FontInfo::incSize on FONT_SIZE_INCREASE");
157 case FONT_SIZE_DECREASE:
158 LYXERR0("Can't FontInfo::incSize on FONT_SIZE_DECREASE");
160 case FONT_SIZE_INHERIT:
161 LYXERR0("Can't FontInfo::incSize on FONT_SIZE_INHERIT");
163 case FONT_SIZE_IGNORE:
164 LYXERR0("Can't FontInfo::incSize on FONT_SIZE_IGNORE");
171 /// Reduce font to fall back to template where possible
172 void FontInfo::reduce(FontInfo const & tmplt)
174 if (family_ == tmplt.family_)
175 family_ = INHERIT_FAMILY;
176 if (series_ == tmplt.series_)
177 series_ = INHERIT_SERIES;
178 if (shape_ == tmplt.shape_)
179 shape_ = INHERIT_SHAPE;
180 if (size_ == tmplt.size_)
181 size_ = FONT_SIZE_INHERIT;
182 if (emph_ == tmplt.emph_)
183 emph_ = FONT_INHERIT;
184 if (underbar_ == tmplt.underbar_)
185 underbar_ = FONT_INHERIT;
186 if (strikeout_ == tmplt.strikeout_)
187 strikeout_ = FONT_INHERIT;
188 if (uuline_ == tmplt.uuline_)
189 uuline_ = FONT_INHERIT;
190 if (uwave_ == tmplt.uwave_)
191 uwave_ = FONT_INHERIT;
192 if (noun_ == tmplt.noun_)
193 noun_ = FONT_INHERIT;
194 if (color_ == tmplt.color_)
195 color_ = Color_inherit;
196 if (background_ == tmplt.background_)
197 background_ = Color_inherit;
201 /// Realize font from a template
202 FontInfo & FontInfo::realize(FontInfo const & tmplt)
204 if ((*this) == inherit_font) {
209 if (family_ == INHERIT_FAMILY)
210 family_ = tmplt.family_;
212 if (series_ == INHERIT_SERIES)
213 series_ = tmplt.series_;
215 if (shape_ == INHERIT_SHAPE)
216 shape_ = tmplt.shape_;
218 if (size_ == FONT_SIZE_INHERIT)
221 if (emph_ == FONT_INHERIT)
224 if (underbar_ == FONT_INHERIT)
225 underbar_ = tmplt.underbar_;
227 if (strikeout_ == FONT_INHERIT)
228 strikeout_ = tmplt.strikeout_;
230 if (uuline_ == FONT_INHERIT)
231 uuline_ = tmplt.uuline_;
233 if (uwave_ == FONT_INHERIT)
234 uwave_ = tmplt.uwave_;
236 if (noun_ == FONT_INHERIT)
239 if (color_ == Color_inherit)
240 color_ = tmplt.color_;
242 if (background_ == Color_inherit)
243 background_ = tmplt.background_;
249 Changer FontInfo::changeColor(ColorCode const color, bool cond)
251 return make_change(color_, color, cond);
255 Changer FontInfo::changeShape(FontShape const shape, bool cond)
257 return make_change(shape_, shape, cond);
261 Changer FontInfo::change(FontInfo font, bool realiz, bool cond)
265 return make_change(*this, font, cond);
269 /// Updates a misc setting according to request
270 static FontState setMisc(FontState newfont,
273 if (newfont == FONT_TOGGLE) {
276 else if (org == FONT_OFF)
279 LYXERR0("Font::setMisc: Need state"
280 " FONT_ON or FONT_OFF to toggle. Setting to FONT_ON");
283 } else if (newfont == FONT_IGNORE)
289 /// Updates font settings according to request
290 void FontInfo::update(FontInfo const & newfont, bool toggleall)
292 if (newfont.family_ == family_ && toggleall)
293 setFamily(INHERIT_FAMILY); // toggle 'back'
294 else if (newfont.family_ != IGNORE_FAMILY)
295 setFamily(newfont.family_);
296 // else it's IGNORE_SHAPE
298 // "Old" behaviour: "Setting" bold will toggle bold on/off.
299 switch (newfont.series_) {
302 if (series_ == BOLD_SERIES && toggleall)
303 setSeries(MEDIUM_SERIES);
305 setSeries(BOLD_SERIES);
309 setSeries(newfont.series_);
315 if (newfont.shape_ == shape_ && toggleall)
316 shape_ = INHERIT_SHAPE; // toggle 'back'
317 else if (newfont.shape_ != IGNORE_SHAPE)
318 shape_ = newfont.shape_;
319 // else it's IGNORE_SHAPE
321 if (newfont.size_ != FONT_SIZE_IGNORE) {
322 if (newfont.size_ == FONT_SIZE_INCREASE)
324 else if (newfont.size_ == FONT_SIZE_DECREASE)
327 size_ = newfont.size_;
330 setEmph(setMisc(newfont.emph_, emph_));
331 setUnderbar(setMisc(newfont.underbar_, underbar_));
332 setStrikeout(setMisc(newfont.strikeout_, strikeout_));
333 setUuline(setMisc(newfont.uuline_, uuline_));
334 setUwave(setMisc(newfont.uwave_, uwave_));
335 setNoun(setMisc(newfont.noun_, noun_));
336 setNumber(setMisc(newfont.number_, number_));
338 if (newfont.color_ == color_ && toggleall)
339 setColor(Color_inherit); // toggle 'back'
340 else if (newfont.color_ != Color_ignore)
341 setColor(newfont.color_);
343 if (newfont.background_ == background_ && toggleall)
344 setBackground(Color_inherit); // toggle 'back'
345 else if (newfont.background_ != Color_ignore)
346 setBackground(newfont.background_);
349 /// Is font resolved?
350 bool FontInfo::resolved() const
352 return (family_ != INHERIT_FAMILY && series_ != INHERIT_SERIES
353 && shape_ != INHERIT_SHAPE && size_ != FONT_SIZE_INHERIT
354 && emph_ != FONT_INHERIT && underbar_ != FONT_INHERIT
355 && uuline_ != FONT_INHERIT && uwave_ != FONT_INHERIT
356 && strikeout_ != FONT_INHERIT && noun_ != FONT_INHERIT
357 && color_ != Color_inherit
358 && background_ != Color_inherit);
362 Color FontInfo::realColor() const
364 if (paint_color_ != Color_none)
366 if (color_ == Color_none)
367 return Color_foreground;
374 void appendSep(string & s1, string const & s2)
378 s1 += s1.empty() ? "" : "\n";
383 string makeCSSTag(string const & key, string const & val)
385 return key + ": " + val + ";";
389 string getFamilyCSS(FontFamily const & f)
396 case TYPEWRITER_FAMILY:
418 string getSeriesCSS(FontSeries const & s)
433 string getShapeCSS(FontShape const & s)
435 string fs = "normal";
436 string fv = "normal";
438 case UP_SHAPE: break;
439 case ITALIC_SHAPE: fs = "italic"; break;
440 case SLANTED_SHAPE: fs = "oblique"; break;
441 case SMALLCAPS_SHAPE: fv = "small-caps"; break;
444 fs = ""; fv = ""; break;
448 appendSep(retval, makeCSSTag("font-style", fs));
450 appendSep(retval, makeCSSTag("font-variant", fv));
455 string getSizeCSS(FontSize const & s)
460 case FONT_SIZE_SCRIPT:
462 case FONT_SIZE_FOOTNOTE:
463 case FONT_SIZE_SMALL:
465 case FONT_SIZE_NORMAL:
467 case FONT_SIZE_LARGE:
469 case FONT_SIZE_LARGER:
470 case FONT_SIZE_LARGEST:
473 case FONT_SIZE_HUGER:
475 case FONT_SIZE_INCREASE:
477 case FONT_SIZE_DECREASE:
479 case FONT_SIZE_IGNORE:
480 case FONT_SIZE_INHERIT:
486 } // namespace anonymous
489 // FIXME This does not yet handle color
490 docstring FontInfo::asCSS() const
493 string tmp = getFamilyCSS(family_);
495 appendSep(retval, makeCSSTag("font-family", tmp));
496 tmp = getSeriesCSS(series_);
498 appendSep(retval, makeCSSTag("font-weight", tmp));
499 appendSep(retval, getShapeCSS(shape_));
500 tmp = getSizeCSS(size_);
502 appendSep(retval, makeCSSTag("font-size", tmp));
503 return from_ascii(retval);
507 // Set family according to lyx format string
508 void setLyXFamily(string const & fam, FontInfo & f)
510 string const s = ascii_lowercase(fam);
513 while (LyXFamilyNames[i] != s &&
514 LyXFamilyNames[i] != string("error"))
516 if (s == LyXFamilyNames[i])
517 f.setFamily(FontFamily(i));
519 LYXERR0("Unknown family `" << s << '\'');
523 // Set series according to lyx format string
524 void setLyXSeries(string const & ser, FontInfo & f)
526 string const s = ascii_lowercase(ser);
529 while (LyXSeriesNames[i] != s &&
530 LyXSeriesNames[i] != string("error")) ++i;
531 if (s == LyXSeriesNames[i]) {
532 f.setSeries(FontSeries(i));
534 LYXERR0("Unknown series `" << s << '\'');
538 // Set shape according to lyx format string
539 void setLyXShape(string const & sha, FontInfo & f)
541 string const s = ascii_lowercase(sha);
544 while (LyXShapeNames[i] != s && LyXShapeNames[i] != string("error"))
546 if (s == LyXShapeNames[i])
547 f.setShape(FontShape(i));
549 LYXERR0("Unknown shape `" << s << '\'');
553 // Set size according to lyx format string
554 void setLyXSize(string const & siz, FontInfo & f)
556 string const s = ascii_lowercase(siz);
558 while (LyXSizeNames[i] != s && LyXSizeNames[i] != string("error"))
560 if (s == LyXSizeNames[i]) {
561 f.setSize(FontSize(i));
563 LYXERR0("Unknown size `" << s << '\'');
567 // Set size according to lyx format string
568 FontState setLyXMisc(string const & siz)
570 string const s = ascii_lowercase(siz);
572 while (LyXMiscNames[i] != s &&
573 LyXMiscNames[i] != string("error")) ++i;
574 if (s == LyXMiscNames[i])
576 LYXERR0("Unknown misc flag `" << s << '\'');
581 /// Sets color after LyX text format
582 void setLyXColor(string const & col, FontInfo & f)
584 f.setColor(lcolor.getFromLyXName(col));
588 // Read a font definition from given file in lyx format
590 FontInfo lyxRead(Lexer & lex, FontInfo const & fi)
594 bool finished = false;
595 while (!finished && lex.isOK() && !error) {
597 string const tok = ascii_lowercase(lex.getString());
601 } else if (tok == "endfont") {
603 } else if (tok == "family") {
605 string const ttok = lex.getString();
606 setLyXFamily(ttok, f);
607 } else if (tok == "series") {
609 string const ttok = lex.getString();
610 setLyXSeries(ttok, f);
611 } else if (tok == "shape") {
613 string const ttok = lex.getString();
614 setLyXShape(ttok, f);
615 } else if (tok == "size") {
617 string const ttok = lex.getString();
619 } else if (tok == "misc") {
621 string const ttok = ascii_lowercase(lex.getString());
623 if (ttok == "no_bar") {
624 f.setUnderbar(FONT_OFF);
625 } else if (ttok == "no_strikeout") {
626 f.setStrikeout(FONT_OFF);
627 } else if (ttok == "no_uuline") {
628 f.setUuline(FONT_OFF);
629 } else if (ttok == "no_uwave") {
630 f.setUwave(FONT_OFF);
631 } else if (ttok == "no_emph") {
633 } else if (ttok == "no_noun") {
635 } else if (ttok == "emph") {
637 } else if (ttok == "underbar") {
638 f.setUnderbar(FONT_ON);
639 } else if (ttok == "strikeout") {
640 f.setStrikeout(FONT_ON);
641 } else if (ttok == "uuline") {
642 f.setUuline(FONT_ON);
643 } else if (ttok == "uwave") {
645 } else if (ttok == "noun") {
648 lex.printError("Illegal misc type");
650 } else if (tok == "color") {
652 string const ttok = lex.getString();
653 setLyXColor(ttok, f);
655 lex.printError("Unknown tag");
663 void lyxWrite(ostream & os, FontInfo const & f, string const & start, int level)
666 for (int i = 0; i < level; ++i)
669 if (f.family() != INHERIT_FAMILY)
670 oss << indent << "\tFamily " << LyXFamilyNames[f.family()]
672 if (f.series() != INHERIT_SERIES)
673 oss << indent << "\tSeries " << LyXSeriesNames[f.series()]
675 if (f.shape() != INHERIT_SHAPE)
676 oss << indent << "\tShape " << LyXShapeNames[f.shape()]
678 if (f.size() != FONT_SIZE_INHERIT)
679 oss << indent << "\tSize " << LyXSizeNames[f.size()]
681 if (f.underbar() == FONT_ON)
682 oss << indent << "\tMisc Underbar\n";
683 else if (f.underbar() == FONT_OFF)
684 oss << indent << "\tMisc No_Bar\n";
685 if (f.strikeout() == FONT_ON)
686 oss << indent << "\tMisc Strikeout\n";
687 else if (f.strikeout() == FONT_OFF)
688 oss << indent << "\tMisc No_Strikeout\n";
689 if (f.uuline() == FONT_ON)
690 oss << indent << "\tMisc Uuline\n";
691 else if (f.uuline() == FONT_OFF)
692 oss << indent << "\tMisc No_Uuline\n";
693 if (f.uwave() == FONT_ON)
694 oss << indent << "\tMisc Uwave\n";
695 else if (f.uwave() == FONT_OFF)
696 oss << indent << "\tMisc No_Uwave\n";
697 if (f.emph() == FONT_ON)
698 oss << indent << "\tMisc Emph\n";
699 else if (f.emph() == FONT_OFF)
700 oss << indent << "\tMisc No_Emph\n";
701 if (f.noun() == FONT_ON)
702 oss << indent << "\tMisc Noun\n";
703 else if (f.noun() == FONT_OFF)
704 oss << indent << "\tMisc No_Noun\n";
705 if (f.color() != Color_inherit && f.color() != Color_none)
706 oss << indent << "\tColor " << lcolor.getLyXName(f.color())
708 if (!oss.str().empty()) {
709 os << indent << start << '\n'
711 << indent << "EndFont\n";