]> git.lyx.org Git - lyx.git/blob - src/lyxfont.C
9c4f2f529718af18db127d741cf4abaaaaf463f4
[lyx.git] / src / lyxfont.C
1 /**
2  * \file lyxfont.C
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Lars Gullik Bjønnes
7  * \author Jean-Marc Lasgouttes
8  * \author Angus Leeming
9  * \author André Pönitz
10  * \author Dekel Tsur
11  *
12  * Full author contact details are available in file CREDITS.
13  */
14
15 #include <config.h>
16
17 #include "lyxfont.h"
18
19 #include "bufferparams.h" // stateText
20 #include "debug.h"
21 #include "gettext.h"
22 #include "language.h"
23 #include "lyxlex.h"
24 #include "lyxrc.h"
25
26 #include "support/lstrings.h"
27
28 #include "support/std_sstream.h"
29
30 using lyx::support::ascii_lowercase;
31 using lyx::support::bformat;
32 using lyx::support::rtrim;
33 using lyx::support::subst;
34
35 using std::endl;
36
37 using std::ostream;
38 using std::ostringstream;
39
40 #ifndef CXX_GLOBAL_CSTD
41 using std::strlen;
42 #endif
43
44 //
45 // Names for the GUI
46 //
47
48 namespace {
49
50 char const * GUIFamilyNames[LyXFont::NUM_FAMILIES + 2 /* default & error */] =
51 { N_("Roman"), N_("Sans Serif"), N_("Typewriter"), N_("Symbol"),
52   "cmr", "cmsy", "cmm", "cmex", "msa", "msb", "eufrak", "wasy",
53   N_("Inherit"), N_("Ignore") };
54
55 char const * GUISeriesNames[4] =
56 { N_("Medium"), N_("Bold"), N_("Inherit"), N_("Ignore") };
57
58 char const * GUIShapeNames[6] =
59 { N_("Upright"), N_("Italic"), N_("Slanted"), N_("Smallcaps"), N_("Inherit"),
60   N_("Ignore") };
61
62 char const * GUISizeNames[14] =
63 { N_("Tiny"), N_("Smallest"), N_("Smaller"), N_("Small"), N_("Normal"), N_("Large"),
64   N_("Larger"), N_("Largest"), N_("Huge"), N_("Huger"), N_("Increase"), N_("Decrease"),
65   N_("Inherit"), N_("Ignore") };
66
67 char const * GUIMiscNames[5] =
68 { N_("Off"), N_("On"), N_("Toggle"), N_("Inherit"), N_("Ignore") };
69
70
71 //
72 // Strings used to read and write .lyx format files
73 //
74 char const * LyXFamilyNames[LyXFont::NUM_FAMILIES + 2 /* default & error */] =
75 { "roman", "sans", "typewriter", "symbol",
76   "cmr", "cmsy", "cmm", "cmex", "msa", "msb", "eufrak", "wasy",
77   "default", "error" };
78
79 char const * LyXSeriesNames[4] =
80 { "medium", "bold", "default", "error" };
81
82 char const * LyXShapeNames[6] =
83 { "up", "italic", "slanted", "smallcaps", "default", "error" };
84
85 char const * LyXSizeNames[14] =
86 { "tiny", "scriptsize", "footnotesize", "small", "normal", "large",
87   "larger", "largest", "huge", "giant",
88   "increase", "decrease", "default", "error" };
89
90 char const * LyXMiscNames[5] =
91 { "off", "on", "toggle", "default", "error" };
92
93 //
94 // Strings used to write LaTeX files
95 //
96 char const * LaTeXFamilyNames[6] =
97 { "textrm", "textsf", "texttt", "error1", "error2", "error3" };
98
99 char const * LaTeXSeriesNames[4] =
100 { "textmd", "textbf", "error4", "error5" };
101
102 char const * LaTeXShapeNames[6] =
103 { "textup", "textit", "textsl", "textsc", "error6", "error7" };
104
105 char const * LaTeXSizeNames[14] =
106 { "tiny", "scriptsize", "footnotesize", "small", "normalsize", "large",
107   "Large", "LARGE", "huge", "Huge", "error8", "error9", "error10", "error11" };
108
109 } // namespace anon
110
111
112 // Initialize static member
113 LyXFont::FontBits LyXFont::sane = {
114         ROMAN_FAMILY,
115         MEDIUM_SERIES,
116         UP_SHAPE,
117         SIZE_NORMAL,
118         LColor::none,
119         OFF,
120         OFF,
121         OFF,
122         OFF };
123
124 // Initialize static member
125 LyXFont::FontBits LyXFont::inherit = {
126         INHERIT_FAMILY,
127         INHERIT_SERIES,
128         INHERIT_SHAPE,
129         INHERIT_SIZE,
130         LColor::inherit,
131         INHERIT,
132         INHERIT,
133         INHERIT,
134         OFF };
135
136 // Initialize static member
137 LyXFont::FontBits LyXFont::ignore = {
138         IGNORE_FAMILY,
139         IGNORE_SERIES,
140         IGNORE_SHAPE,
141         IGNORE_SIZE,
142         LColor::ignore,
143         IGNORE,
144         IGNORE,
145         IGNORE,
146         IGNORE };
147
148
149 bool operator==(LyXFont::FontBits const & lhs,
150                 LyXFont::FontBits const & rhs)
151 {
152         return lhs.family == rhs.family &&
153                 lhs.series == rhs.series &&
154                 lhs.shape == rhs.shape &&
155                 lhs.size == rhs.size &&
156                 lhs.color == rhs.color &&
157                 lhs.emph == rhs.emph &&
158                 lhs.underbar == rhs.underbar &&
159                 lhs.noun == rhs.noun &&
160                 lhs.number == rhs.number;
161 }
162
163
164 LyXFont::LyXFont()
165         : bits(sane), lang(default_language)
166 {}
167
168
169 LyXFont::LyXFont(LyXFont::FONT_INIT1)
170         : bits(inherit), lang(default_language)
171 {}
172
173
174 LyXFont::LyXFont(LyXFont::FONT_INIT2)
175         : bits(ignore), lang(ignore_language)
176 {}
177
178
179 LyXFont::LyXFont(LyXFont::FONT_INIT3)
180         : bits(sane), lang(default_language)
181 {}
182
183
184 LyXFont::LyXFont(LyXFont::FONT_INIT1, Language const * l)
185         : bits(inherit), lang(l)
186 {}
187
188
189 LyXFont::LyXFont(LyXFont::FONT_INIT2, Language const * l)
190         : bits(ignore), lang(l)
191 {}
192
193
194 LyXFont::LyXFont(LyXFont::FONT_INIT3, Language const * l)
195         : bits(sane), lang(l)
196 {}
197
198
199 LyXFont::FONT_MISC_STATE LyXFont::underbar() const
200 {
201         return bits.underbar;
202 }
203
204
205 EnumLColor LyXFont::color() const
206 {
207         return bits.color;
208 }
209
210
211 Language const * LyXFont::language() const
212 {
213         return lang;
214 }
215
216
217 LyXFont::FONT_MISC_STATE LyXFont::number() const
218 {
219         return bits.number;
220 }
221
222
223 bool LyXFont::isRightToLeft() const
224 {
225         return lang->RightToLeft();
226 }
227
228
229 bool LyXFont::isVisibleRightToLeft() const
230 {
231         return (lang->RightToLeft() &&
232                 number() != ON);
233 }
234
235
236 LyXFont & LyXFont::setFamily(LyXFont::FONT_FAMILY f)
237 {
238         bits.family = f;
239         return *this;
240 }
241
242
243 LyXFont & LyXFont::setSeries(LyXFont::FONT_SERIES s)
244 {
245         bits.series = s;
246         return *this;
247 }
248
249
250 LyXFont & LyXFont::setShape(LyXFont::FONT_SHAPE s)
251 {
252         bits.shape = s;
253         return *this;
254 }
255
256
257 LyXFont & LyXFont::setSize(LyXFont::FONT_SIZE s)
258 {
259         bits.size = s;
260         return *this;
261 }
262
263
264 LyXFont & LyXFont::setEmph(LyXFont::FONT_MISC_STATE e)
265 {
266         bits.emph = e;
267         return *this;
268 }
269
270
271 LyXFont & LyXFont::setUnderbar(LyXFont::FONT_MISC_STATE u)
272 {
273         bits.underbar = u;
274         return *this;
275 }
276
277
278 LyXFont & LyXFont::setNoun(LyXFont::FONT_MISC_STATE n)
279 {
280         bits.noun = n;
281         return *this;
282 }
283
284
285 LyXFont & LyXFont::setColor(EnumLColor c)
286 {
287         bits.color = c;
288         return *this;
289 }
290
291
292 LyXFont & LyXFont::setLanguage(Language const * l)
293 {
294         lang = l;
295         return *this;
296 }
297
298
299 LyXFont & LyXFont::setNumber(LyXFont::FONT_MISC_STATE n)
300 {
301         bits.number = n;
302         return *this;
303 }
304
305
306 /// Decreases font size by one
307 LyXFont & LyXFont::decSize()
308 {
309         switch (size()) {
310         case SIZE_HUGER:        setSize(SIZE_HUGE);     break;
311         case SIZE_HUGE:         setSize(SIZE_LARGEST);  break;
312         case SIZE_LARGEST:      setSize(SIZE_LARGER);   break;
313         case SIZE_LARGER:       setSize(SIZE_LARGE);    break;
314         case SIZE_LARGE:        setSize(SIZE_NORMAL);   break;
315         case SIZE_NORMAL:       setSize(SIZE_SMALL);    break;
316         case SIZE_SMALL:        setSize(SIZE_FOOTNOTE); break;
317         case SIZE_FOOTNOTE:     setSize(SIZE_SCRIPT);   break;
318         case SIZE_SCRIPT:       setSize(SIZE_TINY);     break;
319         case SIZE_TINY:         break;
320         case INCREASE_SIZE:
321                 lyxerr << "Can't LyXFont::decSize on INCREASE_SIZE" << endl;
322                 break;
323         case DECREASE_SIZE:
324                 lyxerr <<"Can't LyXFont::decSize on DECREASE_SIZE" << endl;
325                 break;
326         case INHERIT_SIZE:
327                 lyxerr <<"Can't LyXFont::decSize on INHERIT_SIZE" << endl;
328                 break;
329         case IGNORE_SIZE:
330                 lyxerr <<"Can't LyXFont::decSize on IGNORE_SIZE" << endl;
331                 break;
332         }
333         return *this;
334 }
335
336
337 /// Increases font size by one
338 LyXFont & LyXFont::incSize()
339 {
340         switch (size()) {
341         case SIZE_HUGER:        break;
342         case SIZE_HUGE:         setSize(SIZE_HUGER);    break;
343         case SIZE_LARGEST:      setSize(SIZE_HUGE);     break;
344         case SIZE_LARGER:       setSize(SIZE_LARGEST);  break;
345         case SIZE_LARGE:        setSize(SIZE_LARGER);   break;
346         case SIZE_NORMAL:       setSize(SIZE_LARGE);    break;
347         case SIZE_SMALL:        setSize(SIZE_NORMAL);   break;
348         case SIZE_FOOTNOTE:     setSize(SIZE_SMALL);    break;
349         case SIZE_SCRIPT:       setSize(SIZE_FOOTNOTE); break;
350         case SIZE_TINY:         setSize(SIZE_SCRIPT);   break;
351         case INCREASE_SIZE:
352                 lyxerr <<"Can't LyXFont::incSize on INCREASE_SIZE" << endl;
353                 break;
354         case DECREASE_SIZE:
355                 lyxerr <<"Can't LyXFont::incSize on DECREASE_SIZE" << endl;
356                 break;
357         case INHERIT_SIZE:
358                 lyxerr <<"Can't LyXFont::incSize on INHERIT_SIZE" << endl;
359                 break;
360         case IGNORE_SIZE:
361                 lyxerr <<"Can't LyXFont::incSize on IGNORE_SIZE" << endl;
362                 break;
363         }
364         return *this;
365 }
366
367
368 /// Updates a misc setting according to request
369 LyXFont::FONT_MISC_STATE LyXFont::setMisc(FONT_MISC_STATE newfont,
370                                           FONT_MISC_STATE org)
371 {
372         if (newfont == TOGGLE) {
373                 if (org == ON)
374                         return OFF;
375                 else if (org == OFF)
376                         return ON;
377                 else {
378                         lyxerr <<"LyXFont::setMisc: Need state"
379                                 " ON or OFF to toggle. Setting to ON" << endl;
380                         return ON;
381                 }
382         } else if (newfont == IGNORE)
383                 return org;
384         else
385                 return newfont;
386 }
387
388
389 /// Updates font settings according to request
390 void LyXFont::update(LyXFont const & newfont,
391                      Language const * document_language,
392                      bool toggleall)
393 {
394         if (newfont.family() == family() && toggleall)
395                 setFamily(INHERIT_FAMILY); // toggle 'back'
396         else if (newfont.family() != IGNORE_FAMILY)
397                 setFamily(newfont.family());
398         // else it's IGNORE_SHAPE
399
400         // "Old" behaviour: "Setting" bold will toggle bold on/off.
401         switch (newfont.series()) {
402         case BOLD_SERIES:
403                 // We toggle...
404                 if (series() == BOLD_SERIES && toggleall)
405                         setSeries(MEDIUM_SERIES);
406                 else
407                         setSeries(BOLD_SERIES);
408                 break;
409         case MEDIUM_SERIES:
410         case INHERIT_SERIES:
411                 setSeries(newfont.series());
412                 break;
413         case IGNORE_SERIES:
414                 break;
415         }
416
417         if (newfont.shape() == shape() && toggleall)
418                 setShape(INHERIT_SHAPE); // toggle 'back'
419         else if (newfont.shape() != IGNORE_SHAPE)
420                 setShape(newfont.shape());
421         // else it's IGNORE_SHAPE
422
423         if (newfont.size() != IGNORE_SIZE) {
424                 if (newfont.size() == INCREASE_SIZE)
425                         incSize();
426                 else if (newfont.size() == DECREASE_SIZE)
427                         decSize();
428                 else
429                         setSize(newfont.size());
430         }
431
432         setEmph(setMisc(newfont.emph(), emph()));
433         setUnderbar(setMisc(newfont.underbar(), underbar()));
434         setNoun(setMisc(newfont.noun(), noun()));
435
436         setNumber(setMisc(newfont.number(), number()));
437         if (newfont.language() == language() && toggleall)
438                 if (language() == document_language)
439                         setLanguage(default_language);
440                 else
441                         setLanguage(document_language);
442         else if (newfont.language() != ignore_language)
443                 setLanguage(newfont.language());
444
445         if (newfont.color() == color() && toggleall)
446                 setColor(LColor::inherit); // toggle 'back'
447         else if (newfont.color() != LColor::ignore)
448                 setColor(newfont.color());
449 }
450
451
452 /// Reduce font to fall back to template where possible
453 void LyXFont::reduce(LyXFont const & tmplt)
454 {
455         if (family() == tmplt.family())
456                 setFamily(INHERIT_FAMILY);
457         if (series() == tmplt.series())
458                 setSeries(INHERIT_SERIES);
459         if (shape() == tmplt.shape())
460                 setShape(INHERIT_SHAPE);
461         if (size() == tmplt.size())
462                 setSize(INHERIT_SIZE);
463         if (emph() == tmplt.emph())
464                 setEmph(INHERIT);
465         if (underbar() == tmplt.underbar())
466                 setUnderbar(INHERIT);
467         if (noun() == tmplt.noun())
468                 setNoun(INHERIT);
469         if (color() == tmplt.color())
470                 setColor(LColor::inherit);
471 }
472
473
474 /// Realize font from a template
475 LyXFont & LyXFont::realize(LyXFont const & tmplt)
476 {
477         if (bits == inherit) {
478                 bits = tmplt.bits;
479                 return *this;
480         }
481
482         if (bits.family == INHERIT_FAMILY) {
483                 bits.family = tmplt.bits.family;
484         }
485         if (bits.series == INHERIT_SERIES) {
486                 bits.series = tmplt.bits.series;
487         }
488         if (bits.shape == INHERIT_SHAPE) {
489                 bits.shape = tmplt.bits.shape;
490         }
491         if (bits.size == INHERIT_SIZE) {
492                 bits.size = tmplt.bits.size;
493         }
494         if (bits.emph == INHERIT) {
495                 bits.emph = tmplt.bits.emph;
496         }
497         if (bits.underbar == INHERIT) {
498                 bits.underbar = tmplt.bits.underbar;
499         }
500         if (bits.noun == INHERIT) {
501                 bits.noun = tmplt.bits.noun;
502         }
503         if (bits.color == LColor::inherit) {
504                 bits.color = tmplt.bits.color;
505         }
506         return *this;
507 }
508
509
510 /// Is font resolved?
511 bool LyXFont::resolved() const
512 {
513         return (family() != INHERIT_FAMILY && series() != INHERIT_SERIES &&
514                 shape() != INHERIT_SHAPE && size() != INHERIT_SIZE &&
515                 emph() != INHERIT && underbar() != INHERIT &&
516                 noun() != INHERIT &&
517                 color() != LColor::inherit);
518 }
519
520
521 /// Build GUI description of font state
522 string const LyXFont::stateText(BufferParams * params) const
523 {
524         ostringstream os;
525         if (family() != INHERIT_FAMILY)
526                 os << _(GUIFamilyNames[family()]) << ", ";
527         if (series() != INHERIT_SERIES)
528                 os << _(GUISeriesNames[series()]) << ", ";
529         if (shape() != INHERIT_SHAPE)
530                 os << _(GUIShapeNames[shape()]) << ", ";
531         if (size() != INHERIT_SIZE)
532                 os << _(GUISizeNames[size()]) << ", ";
533         if (color() != LColor::inherit)
534                 os << lcolor.getGUIName(color()) << ", ";
535         if (emph() != INHERIT)
536                 os << bformat(_("Emphasis %1$s, "), _(GUIMiscNames[emph()]));
537         if (underbar() != INHERIT)
538                 os << bformat(_("Underline %1$s, "), _(GUIMiscNames[underbar()]));
539         if (noun() != INHERIT)
540                 os << bformat(_("Noun %1$s, "), _(GUIMiscNames[noun()]));
541         if (bits == inherit)
542                 os << _("Default") << ", ";
543         if (!params || (language() != params->language))
544                 os << bformat(_("Language: %1$s, "), _(language()->display()));
545         if (number() != OFF)
546                 os << bformat(_("  Number %1$s"), _(GUIMiscNames[number()]));
547         return rtrim(os.str(), ", ");
548 }
549
550
551 // Set family according to lyx format string
552 LyXFont & LyXFont::setLyXFamily(string const & fam)
553 {
554         string const s = ascii_lowercase(fam);
555
556         int i = 0;
557         while (s != LyXFamilyNames[i] && LyXFamilyNames[i] != "error")
558                 ++i;
559         if (s == LyXFamilyNames[i])
560                 setFamily(LyXFont::FONT_FAMILY(i));
561         else
562                 lyxerr << "LyXFont::setLyXFamily: Unknown family `"
563                        << s << '\'' << endl;
564         return *this;
565 }
566
567
568 // Set series according to lyx format string
569 LyXFont & LyXFont::setLyXSeries(string const & ser)
570 {
571         string const s = ascii_lowercase(ser);
572
573         int i = 0;
574         while (s != LyXSeriesNames[i] && LyXSeriesNames[i] != "error") ++i;
575         if (s == LyXSeriesNames[i]) {
576                 setSeries(LyXFont::FONT_SERIES(i));
577         } else
578                 lyxerr << "LyXFont::setLyXSeries: Unknown series `"
579                        << s << '\'' << endl;
580         return *this;
581 }
582
583
584 // Set shape according to lyx format string
585 LyXFont & LyXFont::setLyXShape(string const & sha)
586 {
587         string const s = ascii_lowercase(sha);
588
589         int i = 0;
590         while (s != LyXShapeNames[i] && LyXShapeNames[i] != "error") ++i;
591         if (s == LyXShapeNames[i]) {
592                 setShape(LyXFont::FONT_SHAPE(i));
593         } else
594                 lyxerr << "LyXFont::setLyXShape: Unknown shape `"
595                        << s << '\'' << endl;
596         return *this;
597 }
598
599
600 // Set size according to lyx format string
601 LyXFont & LyXFont::setLyXSize(string const & siz)
602 {
603         string const s = ascii_lowercase(siz);
604         int i = 0;
605         while (s != LyXSizeNames[i] && LyXSizeNames[i] != "error") ++i;
606         if (s == LyXSizeNames[i]) {
607                 setSize(LyXFont::FONT_SIZE(i));
608         } else
609                 lyxerr << "LyXFont::setLyXSize: Unknown size `"
610                        << s << '\'' << endl;
611         return *this;
612 }
613
614
615 // Set size according to lyx format string
616 LyXFont::FONT_MISC_STATE LyXFont::setLyXMisc(string const & siz)
617 {
618         string const s = ascii_lowercase(siz);
619         int i = 0;
620         while (s != LyXMiscNames[i] && LyXMiscNames[i] != "error") ++i;
621         if (s == LyXMiscNames[i])
622                 return FONT_MISC_STATE(i);
623         lyxerr << "LyXFont::setLyXMisc: Unknown misc flag `"
624                << s << '\'' << endl;
625         return OFF;
626 }
627
628
629 /// Sets color after LyX text format
630 LyXFont & LyXFont::setLyXColor(string const & col)
631 {
632         setColor(lcolor.getFromLyXName(col));
633         return *this;
634 }
635
636
637 // Returns size in latex format
638 string const LyXFont::latexSize() const
639 {
640         return LaTeXSizeNames[size()];
641 }
642
643
644 // Read a font definition from given file in lyx format
645 // Used for layouts
646 LyXFont & LyXFont::lyxRead(LyXLex & lex)
647 {
648         bool error = false;
649         bool finished = false;
650         while (!finished && lex.isOK() && !error) {
651                 lex.next();
652                 string const tok = ascii_lowercase(lex.getString());
653
654                 if (tok.empty()) {
655                         continue;
656                 } else if (tok == "endfont") {
657                         finished = true;
658                 } else if (tok == "family") {
659                         lex.next();
660                         string const ttok = lex.getString();
661                         setLyXFamily(ttok);
662                 } else if (tok == "series") {
663                         lex.next();
664                         string const ttok = lex.getString();
665                         setLyXSeries(ttok);
666                 } else if (tok == "shape") {
667                         lex.next();
668                         string const ttok = lex.getString();
669                         setLyXShape(ttok);
670                 } else if (tok == "size") {
671                         lex.next();
672                         string const ttok = lex.getString();
673                         setLyXSize(ttok);
674                 } else if (tok == "misc") {
675                         lex.next();
676                         string const ttok = ascii_lowercase(lex.getString());
677
678                         if (ttok == "no_bar") {
679                                 setUnderbar(OFF);
680                         } else if (ttok == "no_emph") {
681                                 setEmph(OFF);
682                         } else if (ttok == "no_noun") {
683                                 setNoun(OFF);
684                         } else if (ttok == "emph") {
685                                 setEmph(ON);
686                         } else if (ttok == "underbar") {
687                                 setUnderbar(ON);
688                         } else if (ttok == "noun") {
689                                 setNoun(ON);
690                         } else {
691                                 lex.printError("Illegal misc type `$$Token´");
692                         }
693                 } else if (tok == "color") {
694                         lex.next();
695                         string const ttok = lex.getString();
696                         setLyXColor(ttok);
697                 } else {
698                         lex.printError("Unknown tag `$$Token'");
699                         error = true;
700                 }
701         }
702         return *this;
703 }
704
705
706 /// Writes the changes from this font to orgfont in .lyx format in file
707 void LyXFont::lyxWriteChanges(LyXFont const & orgfont,
708                               ostream & os) const
709 {
710         os << "\n";
711         if (orgfont.family() != family()) {
712                 os << "\\family " << LyXFamilyNames[family()] << " \n";
713         }
714         if (orgfont.series() != series()) {
715                 os << "\\series " << LyXSeriesNames[series()] << " \n";
716         }
717         if (orgfont.shape() != shape()) {
718                 os << "\\shape " << LyXShapeNames[shape()] << " \n";
719         }
720         if (orgfont.size() != size()) {
721                 os << "\\size " << LyXSizeNames[size()] << " \n";
722         }
723         if (orgfont.emph() != emph()) {
724                 os << "\\emph " << LyXMiscNames[emph()] << " \n";
725         }
726         if (orgfont.number() != number()) {
727                 os << "\\numeric " << LyXMiscNames[number()] << " \n";
728         }
729         if (orgfont.underbar() != underbar()) {
730                 // This is only for backwards compatibility
731                 switch (underbar()) {
732                 case OFF:       os << "\\bar no \n"; break;
733                 case ON:        os << "\\bar under \n"; break;
734                 case TOGGLE:    lyxerr << "LyXFont::lyxWriteFontChanges: "
735                                         "TOGGLE should not appear here!"
736                                        << endl;
737                 break;
738                 case INHERIT:   os << "\\bar default \n"; break;
739                 case IGNORE:    lyxerr << "LyXFont::lyxWriteFontChanges: "
740                                         "IGNORE should not appear here!"
741                                        << endl;
742                 break;
743                 }
744         }
745         if (orgfont.noun() != noun()) {
746                 os << "\\noun " << LyXMiscNames[noun()] << " \n";
747         }
748         if (orgfont.color() != color()) {
749                 // To make us file compatible with older
750                 // lyx versions we emit "default" instead
751                 // of "inherit"
752                 string col_str(lcolor.getLyXName(color()));
753                 if (col_str == "inherit") col_str = "default";
754                 os << "\\color " << col_str << "\n";
755         }
756         if (orgfont.language() != language()) {
757                 if (language())
758                         os << "\\lang " << language()->lang() << "\n";
759                 else
760                         os << "\\lang unknown\n";
761         }
762 }
763
764
765 /// Writes the head of the LaTeX needed to impose this font
766 // Returns number of chars written.
767 int LyXFont::latexWriteStartChanges(ostream & os, LyXFont const & base,
768                                     LyXFont const & prev) const
769 {
770         int count = 0;
771         bool env = false;
772
773         if (language()->babel() != base.language()->babel() &&
774             language() != prev.language()) {
775                 if (isRightToLeft() != prev.isRightToLeft()) {
776                         if (isRightToLeft()) {
777                                 os << "\\R{";
778                                 count += 3;
779                         } else {
780                                 os << "\\L{";
781                                 count += 3;
782                         }
783                 } else {
784                         string const tmp =
785                                 subst(lyxrc.language_command_local,
786                                       "$$lang", language()->babel());
787                         os << tmp;
788                         count += tmp.length();
789                 }
790         }
791
792         if (number() == ON && prev.number() != ON &&
793             language()->lang() == "hebrew") {
794                 os << "{\\beginL ";
795                 count += 9;
796         }
797
798         LyXFont f = *this;
799         f.reduce(base);
800
801         if (f.family() != INHERIT_FAMILY) {
802                 os << '\\'
803                    << LaTeXFamilyNames[f.family()]
804                    << '{';
805                 count += strlen(LaTeXFamilyNames[f.family()]) + 2;
806                 env = true; //We have opened a new environment
807         }
808         if (f.series() != INHERIT_SERIES) {
809                 os << '\\'
810                    << LaTeXSeriesNames[f.series()]
811                    << '{';
812                 count += strlen(LaTeXSeriesNames[f.series()]) + 2;
813                 env = true; //We have opened a new environment
814         }
815         if (f.shape() != INHERIT_SHAPE) {
816                 os << '\\'
817                    << LaTeXShapeNames[f.shape()]
818                    << '{';
819                 count += strlen(LaTeXShapeNames[f.shape()]) + 2;
820                 env = true; //We have opened a new environment
821         }
822         if (f.color() != LColor::inherit && f.color() != LColor::ignore) {
823                 os << "\\textcolor{"
824                    << lcolor.getLaTeXName(f.color())
825                    << "}{";
826                 count += lcolor.getLaTeXName(f.color()).length() + 13;
827                 env = true; //We have opened a new environment
828         }
829         if (f.emph() == ON) {
830                 os << "\\emph{";
831                 count += 6;
832                 env = true; //We have opened a new environment
833         }
834         if (f.underbar() == ON) {
835                 os << "\\underbar{";
836                 count += 10;
837                 env = true; //We have opened a new environment
838         }
839         // \noun{} is a LyX special macro
840         if (f.noun() == ON) {
841                 os << "\\noun{";
842                 count += 6;
843                 env = true; //We have opened a new environment
844         }
845         if (f.size() != INHERIT_SIZE) {
846                 // If we didn't open an environment above, we open one here
847                 if (!env) {
848                         os << '{';
849                         ++count;
850                 }
851                 os << '\\'
852                    << LaTeXSizeNames[f.size()]
853                    << ' ';
854                 count += strlen(LaTeXSizeNames[f.size()]) + 2;
855         }
856         return count;
857 }
858
859
860 /// Writes ending block of LaTeX needed to close use of this font
861 // Returns number of chars written
862 // This one corresponds to latexWriteStartChanges(). (Asger)
863 int LyXFont::latexWriteEndChanges(ostream & os, LyXFont const & base,
864                                   LyXFont const & next) const
865 {
866         int count = 0;
867         bool env = false;
868
869         // reduce the current font to changes against the base
870         // font (of the layout). We use a temporary for this to
871         // avoid changing this font instance, as that would break
872         LyXFont f = *this;
873         f.reduce(base);
874
875         if (f.family() != INHERIT_FAMILY) {
876                 os << '}';
877                 ++count;
878                 env = true; // Size change need not bother about closing env.
879         }
880         if (f.series() != INHERIT_SERIES) {
881                 os << '}';
882                 ++count;
883                 env = true; // Size change need not bother about closing env.
884         }
885         if (f.shape() != INHERIT_SHAPE) {
886                 os << '}';
887                 ++count;
888                 env = true; // Size change need not bother about closing env.
889         }
890         if (f.color() != LColor::inherit && f.color() != LColor::ignore) {
891                 os << '}';
892                 ++count;
893                 env = true; // Size change need not bother about closing env.
894         }
895         if (f.emph() == ON) {
896                 os << '}';
897                 ++count;
898                 env = true; // Size change need not bother about closing env.
899         }
900         if (f.underbar() == ON) {
901                 os << '}';
902                 ++count;
903                 env = true; // Size change need not bother about closing env.
904         }
905         if (f.noun() == ON) {
906                 os << '}';
907                 ++count;
908                 env = true; // Size change need not bother about closing env.
909         }
910         if (f.size() != INHERIT_SIZE) {
911                 // We only have to close if only size changed
912                 if (!env) {
913                         os << '}';
914                         ++count;
915                 }
916         }
917
918         if (number() == ON && next.number() != ON &&
919             language()->lang() == "hebrew") {
920                 os << "\\endL}";
921                 count += 6;
922         }
923
924         if (language() != base.language() && language() != next.language()) {
925                 os << '}';
926                 ++count;
927         }
928
929         return count;
930 }
931
932
933 EnumLColor LyXFont::realColor() const
934 {
935         if (color() == LColor::none)
936                 return LColor::foreground;
937         return color();
938 }
939
940
941 // Convert logical attributes to concrete shape attribute
942 LyXFont::FONT_SHAPE LyXFont::realShape() const
943 {
944         register FONT_SHAPE s = shape();
945
946         if (emph() == ON) {
947                 if (s == UP_SHAPE)
948                         s = ITALIC_SHAPE;
949                 else
950                         s = UP_SHAPE;
951         }
952         if (noun() == ON)
953                 s = SMALLCAPS_SHAPE;
954         return s;
955 }
956
957
958 ostream & operator<<(ostream & o, LyXFont::FONT_MISC_STATE fms)
959 {
960         return o << int(fms);
961 }