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