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