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