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