]> git.lyx.org Git - lyx.git/blob - src/lyxfont.C
small stuff, whitespace & consistent naming
[lyx.git] / src / lyxfont.C
1 /**
2  * \file src/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 "LColor.h"
24 #include "lyxlex.h"
25 #include "lyxrc.h"
26
27 #include "support/lstrings.h"
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 using std::string;
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 LColor_color LyXFont::color() const
206 {
207         return LColor::color(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 void LyXFont::setFamily(LyXFont::FONT_FAMILY f)
237 {
238         bits.family = f;
239 }
240
241
242 void LyXFont::setSeries(LyXFont::FONT_SERIES s)
243 {
244         bits.series = s;
245 }
246
247
248 void LyXFont::setShape(LyXFont::FONT_SHAPE s)
249 {
250         bits.shape = s;
251 }
252
253
254 void LyXFont::setSize(LyXFont::FONT_SIZE s)
255 {
256         bits.size = s;
257 }
258
259
260 void LyXFont::setEmph(LyXFont::FONT_MISC_STATE e)
261 {
262         bits.emph = e;
263 }
264
265
266 void LyXFont::setUnderbar(LyXFont::FONT_MISC_STATE u)
267 {
268         bits.underbar = u;
269 }
270
271
272 void LyXFont::setNoun(LyXFont::FONT_MISC_STATE n)
273 {
274         bits.noun = n;
275 }
276
277
278 void LyXFont::setColor(LColor_color c)
279 {
280         bits.color = int(c);
281 }
282
283
284 void LyXFont::setLanguage(Language const * l)
285 {
286         lang = l;
287 }
288
289
290 void LyXFont::setNumber(LyXFont::FONT_MISC_STATE n)
291 {
292         bits.number = n;
293 }
294
295
296 /// Decreases font size by one
297 LyXFont & LyXFont::decSize()
298 {
299         switch (size()) {
300         case SIZE_HUGER:        setSize(SIZE_HUGE);     break;
301         case SIZE_HUGE:         setSize(SIZE_LARGEST);  break;
302         case SIZE_LARGEST:      setSize(SIZE_LARGER);   break;
303         case SIZE_LARGER:       setSize(SIZE_LARGE);    break;
304         case SIZE_LARGE:        setSize(SIZE_NORMAL);   break;
305         case SIZE_NORMAL:       setSize(SIZE_SMALL);    break;
306         case SIZE_SMALL:        setSize(SIZE_FOOTNOTE); break;
307         case SIZE_FOOTNOTE:     setSize(SIZE_SCRIPT);   break;
308         case SIZE_SCRIPT:       setSize(SIZE_TINY);     break;
309         case SIZE_TINY:         break;
310         case INCREASE_SIZE:
311                 lyxerr << "Can't LyXFont::decSize on INCREASE_SIZE" << endl;
312                 break;
313         case DECREASE_SIZE:
314                 lyxerr <<"Can't LyXFont::decSize on DECREASE_SIZE" << endl;
315                 break;
316         case INHERIT_SIZE:
317                 lyxerr <<"Can't LyXFont::decSize on INHERIT_SIZE" << endl;
318                 break;
319         case IGNORE_SIZE:
320                 lyxerr <<"Can't LyXFont::decSize on IGNORE_SIZE" << endl;
321                 break;
322         }
323         return *this;
324 }
325
326
327 /// Increases font size by one
328 LyXFont & LyXFont::incSize()
329 {
330         switch (size()) {
331         case SIZE_HUGER:        break;
332         case SIZE_HUGE:         setSize(SIZE_HUGER);    break;
333         case SIZE_LARGEST:      setSize(SIZE_HUGE);     break;
334         case SIZE_LARGER:       setSize(SIZE_LARGEST);  break;
335         case SIZE_LARGE:        setSize(SIZE_LARGER);   break;
336         case SIZE_NORMAL:       setSize(SIZE_LARGE);    break;
337         case SIZE_SMALL:        setSize(SIZE_NORMAL);   break;
338         case SIZE_FOOTNOTE:     setSize(SIZE_SMALL);    break;
339         case SIZE_SCRIPT:       setSize(SIZE_FOOTNOTE); break;
340         case SIZE_TINY:         setSize(SIZE_SCRIPT);   break;
341         case INCREASE_SIZE:
342                 lyxerr <<"Can't LyXFont::incSize on INCREASE_SIZE" << endl;
343                 break;
344         case DECREASE_SIZE:
345                 lyxerr <<"Can't LyXFont::incSize on DECREASE_SIZE" << endl;
346                 break;
347         case INHERIT_SIZE:
348                 lyxerr <<"Can't LyXFont::incSize on INHERIT_SIZE" << endl;
349                 break;
350         case IGNORE_SIZE:
351                 lyxerr <<"Can't LyXFont::incSize on IGNORE_SIZE" << endl;
352                 break;
353         }
354         return *this;
355 }
356
357
358 /// Updates a misc setting according to request
359 LyXFont::FONT_MISC_STATE LyXFont::setMisc(FONT_MISC_STATE newfont,
360                                           FONT_MISC_STATE org)
361 {
362         if (newfont == TOGGLE) {
363                 if (org == ON)
364                         return OFF;
365                 else if (org == OFF)
366                         return ON;
367                 else {
368                         lyxerr <<"LyXFont::setMisc: Need state"
369                                 " ON or OFF to toggle. Setting to ON" << endl;
370                         return ON;
371                 }
372         } else if (newfont == IGNORE)
373                 return org;
374         else
375                 return newfont;
376 }
377
378
379 /// Updates font settings according to request
380 void LyXFont::update(LyXFont const & newfont,
381                      Language const * document_language,
382                      bool toggleall)
383 {
384         if (newfont.family() == family() && toggleall)
385                 setFamily(INHERIT_FAMILY); // toggle 'back'
386         else if (newfont.family() != IGNORE_FAMILY)
387                 setFamily(newfont.family());
388         // else it's IGNORE_SHAPE
389
390         // "Old" behaviour: "Setting" bold will toggle bold on/off.
391         switch (newfont.series()) {
392         case BOLD_SERIES:
393                 // We toggle...
394                 if (series() == BOLD_SERIES && toggleall)
395                         setSeries(MEDIUM_SERIES);
396                 else
397                         setSeries(BOLD_SERIES);
398                 break;
399         case MEDIUM_SERIES:
400         case INHERIT_SERIES:
401                 setSeries(newfont.series());
402                 break;
403         case IGNORE_SERIES:
404                 break;
405         }
406
407         if (newfont.shape() == shape() && toggleall)
408                 setShape(INHERIT_SHAPE); // toggle 'back'
409         else if (newfont.shape() != IGNORE_SHAPE)
410                 setShape(newfont.shape());
411         // else it's IGNORE_SHAPE
412
413         if (newfont.size() != IGNORE_SIZE) {
414                 if (newfont.size() == INCREASE_SIZE)
415                         incSize();
416                 else if (newfont.size() == DECREASE_SIZE)
417                         decSize();
418                 else
419                         setSize(newfont.size());
420         }
421
422         setEmph(setMisc(newfont.emph(), emph()));
423         setUnderbar(setMisc(newfont.underbar(), underbar()));
424         setNoun(setMisc(newfont.noun(), noun()));
425
426         setNumber(setMisc(newfont.number(), number()));
427         if (newfont.language() == language() && toggleall)
428                 if (language() == document_language)
429                         setLanguage(default_language);
430                 else
431                         setLanguage(document_language);
432         else if (newfont.language() != ignore_language)
433                 setLanguage(newfont.language());
434
435         if (newfont.color() == color() && toggleall)
436                 setColor(LColor::inherit); // toggle 'back'
437         else if (newfont.color() != LColor::ignore)
438                 setColor(newfont.color());
439 }
440
441
442 /// Reduce font to fall back to template where possible
443 void LyXFont::reduce(LyXFont const & tmplt)
444 {
445         if (family() == tmplt.family())
446                 setFamily(INHERIT_FAMILY);
447         if (series() == tmplt.series())
448                 setSeries(INHERIT_SERIES);
449         if (shape() == tmplt.shape())
450                 setShape(INHERIT_SHAPE);
451         if (size() == tmplt.size())
452                 setSize(INHERIT_SIZE);
453         if (emph() == tmplt.emph())
454                 setEmph(INHERIT);
455         if (underbar() == tmplt.underbar())
456                 setUnderbar(INHERIT);
457         if (noun() == tmplt.noun())
458                 setNoun(INHERIT);
459         if (color() == tmplt.color())
460                 setColor(LColor::inherit);
461 }
462
463
464 /// Realize font from a template
465 LyXFont & LyXFont::realize(LyXFont const & tmplt)
466 {
467         if (bits == inherit) {
468                 bits = tmplt.bits;
469                 return *this;
470         }
471
472         if (bits.family == INHERIT_FAMILY) {
473                 bits.family = tmplt.bits.family;
474         }
475         if (bits.series == INHERIT_SERIES) {
476                 bits.series = tmplt.bits.series;
477         }
478         if (bits.shape == INHERIT_SHAPE) {
479                 bits.shape = tmplt.bits.shape;
480         }
481         if (bits.size == INHERIT_SIZE) {
482                 bits.size = tmplt.bits.size;
483         }
484         if (bits.emph == INHERIT) {
485                 bits.emph = tmplt.bits.emph;
486         }
487         if (bits.underbar == INHERIT) {
488                 bits.underbar = tmplt.bits.underbar;
489         }
490         if (bits.noun == INHERIT) {
491                 bits.noun = tmplt.bits.noun;
492         }
493         if (bits.color == LColor::inherit) {
494                 bits.color = tmplt.bits.color;
495         }
496         return *this;
497 }
498
499
500 /// Is font resolved?
501 bool LyXFont::resolved() const
502 {
503         return (family() != INHERIT_FAMILY && series() != INHERIT_SERIES &&
504                 shape() != INHERIT_SHAPE && size() != INHERIT_SIZE &&
505                 emph() != INHERIT && underbar() != INHERIT &&
506                 noun() != INHERIT &&
507                 color() != LColor::inherit);
508 }
509
510
511 /// Build GUI description of font state
512 string const LyXFont::stateText(BufferParams * params) const
513 {
514         ostringstream os;
515         if (family() != INHERIT_FAMILY)
516                 os << _(GUIFamilyNames[family()]) << ", ";
517         if (series() != INHERIT_SERIES)
518                 os << _(GUISeriesNames[series()]) << ", ";
519         if (shape() != INHERIT_SHAPE)
520                 os << _(GUIShapeNames[shape()]) << ", ";
521         if (size() != INHERIT_SIZE)
522                 os << _(GUISizeNames[size()]) << ", ";
523         if (color() != LColor::inherit)
524                 os << lcolor.getGUIName(color()) << ", ";
525         if (emph() != INHERIT)
526                 os << bformat(_("Emphasis %1$s, "), _(GUIMiscNames[emph()]));
527         if (underbar() != INHERIT)
528                 os << bformat(_("Underline %1$s, "), _(GUIMiscNames[underbar()]));
529         if (noun() != INHERIT)
530                 os << bformat(_("Noun %1$s, "), _(GUIMiscNames[noun()]));
531         if (bits == inherit)
532                 os << _("Default") << ", ";
533         if (!params || (language() != params->language))
534                 os << bformat(_("Language: %1$s, "), _(language()->display()));
535         if (number() != OFF)
536                 os << bformat(_("  Number %1$s"), _(GUIMiscNames[number()]));
537         return rtrim(os.str(), ", ");
538 }
539
540
541 // Set family according to lyx format string
542 LyXFont & LyXFont::setLyXFamily(string const & fam)
543 {
544         string const s = ascii_lowercase(fam);
545
546         int i = 0;
547         while (s != LyXFamilyNames[i] && LyXFamilyNames[i] != "error")
548                 ++i;
549         if (s == LyXFamilyNames[i])
550                 setFamily(LyXFont::FONT_FAMILY(i));
551         else
552                 lyxerr << "LyXFont::setLyXFamily: Unknown family `"
553                        << s << '\'' << endl;
554         return *this;
555 }
556
557
558 // Set series according to lyx format string
559 LyXFont & LyXFont::setLyXSeries(string const & ser)
560 {
561         string const s = ascii_lowercase(ser);
562
563         int i = 0;
564         while (s != LyXSeriesNames[i] && LyXSeriesNames[i] != "error") ++i;
565         if (s == LyXSeriesNames[i]) {
566                 setSeries(LyXFont::FONT_SERIES(i));
567         } else
568                 lyxerr << "LyXFont::setLyXSeries: Unknown series `"
569                        << s << '\'' << endl;
570         return *this;
571 }
572
573
574 // Set shape according to lyx format string
575 LyXFont & LyXFont::setLyXShape(string const & sha)
576 {
577         string const s = ascii_lowercase(sha);
578
579         int i = 0;
580         while (s != LyXShapeNames[i] && LyXShapeNames[i] != "error") ++i;
581         if (s == LyXShapeNames[i]) {
582                 setShape(LyXFont::FONT_SHAPE(i));
583         } else
584                 lyxerr << "LyXFont::setLyXShape: Unknown shape `"
585                        << s << '\'' << endl;
586         return *this;
587 }
588
589
590 // Set size according to lyx format string
591 LyXFont & LyXFont::setLyXSize(string const & siz)
592 {
593         string const s = ascii_lowercase(siz);
594         int i = 0;
595         while (s != LyXSizeNames[i] && LyXSizeNames[i] != "error") ++i;
596         if (s == LyXSizeNames[i]) {
597                 setSize(LyXFont::FONT_SIZE(i));
598         } else
599                 lyxerr << "LyXFont::setLyXSize: Unknown size `"
600                        << s << '\'' << endl;
601         return *this;
602 }
603
604
605 // Set size according to lyx format string
606 LyXFont::FONT_MISC_STATE LyXFont::setLyXMisc(string const & siz)
607 {
608         string const s = ascii_lowercase(siz);
609         int i = 0;
610         while (s != LyXMiscNames[i] && LyXMiscNames[i] != "error") ++i;
611         if (s == LyXMiscNames[i])
612                 return FONT_MISC_STATE(i);
613         lyxerr << "LyXFont::setLyXMisc: Unknown misc flag `"
614                << s << '\'' << endl;
615         return OFF;
616 }
617
618
619 /// Sets color after LyX text format
620 LyXFont & LyXFont::setLyXColor(string const & col)
621 {
622         setColor(lcolor.getFromLyXName(col));
623         return *this;
624 }
625
626
627 // Returns size in latex format
628 string const LyXFont::latexSize() const
629 {
630         return LaTeXSizeNames[size()];
631 }
632
633
634 // Read a font definition from given file in lyx format
635 // Used for layouts
636 LyXFont & LyXFont::lyxRead(LyXLex & lex)
637 {
638         bool error = false;
639         bool finished = false;
640         while (!finished && lex.isOK() && !error) {
641                 lex.next();
642                 string const tok = ascii_lowercase(lex.getString());
643
644                 if (tok.empty()) {
645                         continue;
646                 } else if (tok == "endfont") {
647                         finished = true;
648                 } else if (tok == "family") {
649                         lex.next();
650                         string const ttok = lex.getString();
651                         setLyXFamily(ttok);
652                 } else if (tok == "series") {
653                         lex.next();
654                         string const ttok = lex.getString();
655                         setLyXSeries(ttok);
656                 } else if (tok == "shape") {
657                         lex.next();
658                         string const ttok = lex.getString();
659                         setLyXShape(ttok);
660                 } else if (tok == "size") {
661                         lex.next();
662                         string const ttok = lex.getString();
663                         setLyXSize(ttok);
664                 } else if (tok == "misc") {
665                         lex.next();
666                         string const ttok = ascii_lowercase(lex.getString());
667
668                         if (ttok == "no_bar") {
669                                 setUnderbar(OFF);
670                         } else if (ttok == "no_emph") {
671                                 setEmph(OFF);
672                         } else if (ttok == "no_noun") {
673                                 setNoun(OFF);
674                         } else if (ttok == "emph") {
675                                 setEmph(ON);
676                         } else if (ttok == "underbar") {
677                                 setUnderbar(ON);
678                         } else if (ttok == "noun") {
679                                 setNoun(ON);
680                         } else {
681                                 lex.printError("Illegal misc type `$$Token´");
682                         }
683                 } else if (tok == "color") {
684                         lex.next();
685                         string const ttok = lex.getString();
686                         setLyXColor(ttok);
687                 } else {
688                         lex.printError("Unknown tag `$$Token'");
689                         error = true;
690                 }
691         }
692         return *this;
693 }
694
695
696 /// Writes the changes from this font to orgfont in .lyx format in file
697 void LyXFont::lyxWriteChanges(LyXFont const & orgfont,
698                               ostream & os) const
699 {
700         os << "\n";
701         if (orgfont.family() != family()) {
702                 os << "\\family " << LyXFamilyNames[family()] << " \n";
703         }
704         if (orgfont.series() != series()) {
705                 os << "\\series " << LyXSeriesNames[series()] << " \n";
706         }
707         if (orgfont.shape() != shape()) {
708                 os << "\\shape " << LyXShapeNames[shape()] << " \n";
709         }
710         if (orgfont.size() != size()) {
711                 os << "\\size " << LyXSizeNames[size()] << " \n";
712         }
713         if (orgfont.emph() != emph()) {
714                 os << "\\emph " << LyXMiscNames[emph()] << " \n";
715         }
716         if (orgfont.number() != number()) {
717                 os << "\\numeric " << LyXMiscNames[number()] << " \n";
718         }
719         if (orgfont.underbar() != underbar()) {
720                 // This is only for backwards compatibility
721                 switch (underbar()) {
722                 case OFF:       os << "\\bar no \n"; break;
723                 case ON:        os << "\\bar under \n"; break;
724                 case TOGGLE:    lyxerr << "LyXFont::lyxWriteFontChanges: "
725                                         "TOGGLE should not appear here!"
726                                        << endl;
727                 break;
728                 case INHERIT:   os << "\\bar default \n"; break;
729                 case IGNORE:    lyxerr << "LyXFont::lyxWriteFontChanges: "
730                                         "IGNORE should not appear here!"
731                                        << endl;
732                 break;
733                 }
734         }
735         if (orgfont.noun() != noun()) {
736                 os << "\\noun " << LyXMiscNames[noun()] << " \n";
737         }
738         if (orgfont.color() != color()) {
739                 // To make us file compatible with older
740                 // lyx versions we emit "default" instead
741                 // of "inherit"
742                 string col_str(lcolor.getLyXName(color()));
743                 if (col_str == "inherit") col_str = "default";
744                 os << "\\color " << col_str << "\n";
745         }
746         if (orgfont.language() != language()) {
747                 if (language())
748                         os << "\\lang " << language()->lang() << "\n";
749                 else
750                         os << "\\lang unknown\n";
751         }
752 }
753
754
755 /// Writes the head of the LaTeX needed to impose this font
756 // Returns number of chars written.
757 int LyXFont::latexWriteStartChanges(ostream & os, LyXFont const & base,
758                                     LyXFont const & prev) const
759 {
760         int count = 0;
761         bool env = false;
762
763         if (language()->babel() != base.language()->babel() &&
764             language() != prev.language()) {
765                 if (isRightToLeft() != prev.isRightToLeft()) {
766                         if (isRightToLeft()) {
767                                 os << "\\R{";
768                                 count += 3;
769                         } else {
770                                 os << "\\L{";
771                                 count += 3;
772                         }
773                 } else {
774                         string const tmp =
775                                 subst(lyxrc.language_command_local,
776                                       "$$lang", language()->babel());
777                         os << tmp;
778                         count += tmp.length();
779                 }
780         }
781
782         if (number() == ON && prev.number() != ON &&
783             language()->lang() == "hebrew") {
784                 os << "{\\beginL ";
785                 count += 9;
786         }
787
788         LyXFont f = *this;
789         f.reduce(base);
790
791         if (f.family() != INHERIT_FAMILY) {
792                 os << '\\'
793                    << LaTeXFamilyNames[f.family()]
794                    << '{';
795                 count += strlen(LaTeXFamilyNames[f.family()]) + 2;
796                 env = true; //We have opened a new environment
797         }
798         if (f.series() != INHERIT_SERIES) {
799                 os << '\\'
800                    << LaTeXSeriesNames[f.series()]
801                    << '{';
802                 count += strlen(LaTeXSeriesNames[f.series()]) + 2;
803                 env = true; //We have opened a new environment
804         }
805         if (f.shape() != INHERIT_SHAPE) {
806                 os << '\\'
807                    << LaTeXShapeNames[f.shape()]
808                    << '{';
809                 count += strlen(LaTeXShapeNames[f.shape()]) + 2;
810                 env = true; //We have opened a new environment
811         }
812         if (f.color() != LColor::inherit && f.color() != LColor::ignore) {
813                 os << "\\textcolor{"
814                    << lcolor.getLaTeXName(f.color())
815                    << "}{";
816                 count += lcolor.getLaTeXName(f.color()).length() + 13;
817                 env = true; //We have opened a new environment
818         }
819         if (f.emph() == ON) {
820                 os << "\\emph{";
821                 count += 6;
822                 env = true; //We have opened a new environment
823         }
824         if (f.underbar() == ON) {
825                 os << "\\underbar{";
826                 count += 10;
827                 env = true; //We have opened a new environment
828         }
829         // \noun{} is a LyX special macro
830         if (f.noun() == ON) {
831                 os << "\\noun{";
832                 count += 6;
833                 env = true; //We have opened a new environment
834         }
835         if (f.size() != INHERIT_SIZE) {
836                 // If we didn't open an environment above, we open one here
837                 if (!env) {
838                         os << '{';
839                         ++count;
840                 }
841                 os << '\\'
842                    << LaTeXSizeNames[f.size()]
843                    << ' ';
844                 count += strlen(LaTeXSizeNames[f.size()]) + 2;
845         }
846         return count;
847 }
848
849
850 /// Writes ending block of LaTeX needed to close use of this font
851 // Returns number of chars written
852 // This one corresponds to latexWriteStartChanges(). (Asger)
853 int LyXFont::latexWriteEndChanges(ostream & os, LyXFont const & base,
854                                   LyXFont const & next) const
855 {
856         int count = 0;
857         bool env = false;
858
859         // reduce the current font to changes against the base
860         // font (of the layout). We use a temporary for this to
861         // avoid changing this font instance, as that would break
862         LyXFont f = *this;
863         f.reduce(base);
864
865         if (f.family() != INHERIT_FAMILY) {
866                 os << '}';
867                 ++count;
868                 env = true; // Size change need not bother about closing env.
869         }
870         if (f.series() != INHERIT_SERIES) {
871                 os << '}';
872                 ++count;
873                 env = true; // Size change need not bother about closing env.
874         }
875         if (f.shape() != INHERIT_SHAPE) {
876                 os << '}';
877                 ++count;
878                 env = true; // Size change need not bother about closing env.
879         }
880         if (f.color() != LColor::inherit && f.color() != LColor::ignore) {
881                 os << '}';
882                 ++count;
883                 env = true; // Size change need not bother about closing env.
884         }
885         if (f.emph() == ON) {
886                 os << '}';
887                 ++count;
888                 env = true; // Size change need not bother about closing env.
889         }
890         if (f.underbar() == ON) {
891                 os << '}';
892                 ++count;
893                 env = true; // Size change need not bother about closing env.
894         }
895         if (f.noun() == ON) {
896                 os << '}';
897                 ++count;
898                 env = true; // Size change need not bother about closing env.
899         }
900         if (f.size() != INHERIT_SIZE) {
901                 // We only have to close if only size changed
902                 if (!env) {
903                         os << '}';
904                         ++count;
905                 }
906         }
907
908         if (number() == ON && next.number() != ON &&
909             language()->lang() == "hebrew") {
910                 os << "\\endL}";
911                 count += 6;
912         }
913
914         if (language() != base.language() && language() != next.language()) {
915                 os << '}';
916                 ++count;
917         }
918
919         return count;
920 }
921
922
923 LColor_color LyXFont::realColor() const
924 {
925         if (color() == LColor::none)
926                 return LColor::foreground;
927         return color();
928 }
929
930
931 // Convert logical attributes to concrete shape attribute
932 LyXFont::FONT_SHAPE LyXFont::realShape() const
933 {
934         register FONT_SHAPE s = shape();
935
936         if (emph() == ON) {
937                 if (s == UP_SHAPE)
938                         s = ITALIC_SHAPE;
939                 else
940                         s = UP_SHAPE;
941         }
942         if (noun() == ON)
943                 s = SMALLCAPS_SHAPE;
944         return s;
945 }
946
947
948 ostream & operator<<(ostream & os, LyXFont::FONT_MISC_STATE fms)
949 {
950         return os << int(fms);
951 }
952
953
954 std::ostream & operator<<(std::ostream & os, LyXFont const & font)
955 {
956         return os << "font:"
957                 << " family " << font.bits.family
958                 << " series " << font.bits.series
959                 << " shape " << font.bits.shape
960                 << " size " << font.bits.size
961                 << " color " << font.bits.color
962                 << " emph " << font.bits.emph
963                 << " underbar " << font.bits.underbar
964                 << " noun " << font.bits.noun
965                 << " number " << font.bits.number
966                 << " lang: " << (font.lang ? font.lang->lang() : 0);
967 }