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