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