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