]> git.lyx.org Git - lyx.git/blob - src/lyxfont.C
fix lyxalgo.h, dra pagebreak with text on line, change the math_deco_search a bit
[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-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 int LyXFont::latexWriteStartChanges(ostream & os, LyXFont const & base,
667                                     LyXFont const & prev) const
668 {
669         LyXFont f = *this;
670         f.reduce(base);
671         
672         if (f.bits == inherit)
673                 return 0;
674         
675         int count = 0;
676         bool env = false;
677
678         FONT_DIRECTION direction = f.direction();
679         if (direction != prev.direction()) {
680                 if (direction == LTR_DIR) {
681                         os << "\\L{";
682                         count += 3;
683                         env = true; //We have opened a new environment
684                 }
685                 if (direction == RTL_DIR) {
686                         os << "\\R{";
687                         count += 3;
688                         env = true; //We have opened a new environment
689                 }
690         }
691
692         if (f.family() != INHERIT_FAMILY) {
693                 os << '\\'
694                    << LaTeXFamilyNames[f.family()]
695                    << '{';
696                 count += LaTeXFamilyNames[f.family()].length() + 2;
697                 env = true; //We have opened a new environment
698         }
699         if (f.series() != INHERIT_SERIES) {
700                 os << '\\'
701                    << LaTeXSeriesNames[f.series()]
702                    << '{';
703                 count += LaTeXSeriesNames[f.series()].length() + 2;
704                 env = true; //We have opened a new environment
705         }
706         if (f.shape() != INHERIT_SHAPE) {
707                 os << '\\'
708                    << LaTeXShapeNames[f.shape()]
709                    << '{';
710                 count += LaTeXShapeNames[f.shape()].length() + 2;
711                 env = true; //We have opened a new environment
712         }
713         if (f.color() != LColor::inherit) {
714                 os << "\\textcolor{"
715                    << lcolor.getLaTeXName(f.color())
716                    << "}{";
717                 count += lcolor.getLaTeXName(f.color()).length() + 13;
718                 env = true; //We have opened a new environment
719         }
720         if (f.emph() == ON) {
721                 os << "\\emph{";
722                 count += 6;
723                 env = true; //We have opened a new environment
724         }
725         if (f.underbar() == ON) {
726                 os << "\\underbar{";
727                 count += 10;
728                 env = true; //We have opened a new environment
729         }
730         // \noun{} is a LyX special macro
731         if (f.noun() == ON) {
732                 os << "\\noun{";
733                 count += 8;
734                 env = true; //We have opened a new environment
735         }
736         if (f.size() != INHERIT_SIZE) {
737                 // If we didn't open an environment above, we open one here
738                 if (!env) {
739                         os << '{';
740                         ++count;
741                 }
742                 os << '\\'
743                    << LaTeXSizeNames[f.size()]
744                    << ' ';
745                 count += LaTeXSizeNames[f.size()].length() + 2;
746         }
747         return count;
748 }
749
750
751 /// Writes ending block of LaTeX needed to close use of this font
752 // Returns number of chars written
753 // This one corresponds to latexWriteStartChanges(). (Asger)
754 int LyXFont::latexWriteEndChanges(ostream & os, LyXFont const & base,
755                                   LyXFont const & next) const
756 {
757         LyXFont f = *this; // why do you need this?
758         f.reduce(base); // why isn't this just "reduce(base);" (Lgb)
759         // Because this function is const. Everything breaks if this
760         // method changes the font it represents. There is no speed penalty
761         // by using the temporary. (Asger)
762
763         if (f.bits == inherit)
764                 return 0;
765         
766         int count = 0;
767         bool env = false;
768
769         FONT_DIRECTION direction = f.direction();
770         if ( direction != next.direction()
771             && (direction == RTL_DIR || direction == LTR_DIR) ) {
772                 os << '}';
773                 ++count;
774                 env = true; // Size change need not bother about closing env.
775         }
776
777         if (f.family() != INHERIT_FAMILY) {
778                 os << '}';
779                 ++count;
780                 env = true; // Size change need not bother about closing env.
781         }
782         if (f.series() != INHERIT_SERIES) {
783                 os << '}';
784                 ++count;
785                 env = true; // Size change need not bother about closing env.
786         }
787         if (f.shape() != INHERIT_SHAPE) {
788                 os << '}';
789                 ++count;
790                 env = true; // Size change need not bother about closing env.
791         }
792         if (f.color() != LColor::inherit) {
793                 os << '}';
794                 ++count;
795                 env = true; // Size change need not bother about closing env.
796         }
797         if (f.emph() == ON) {
798                 os << '}';
799                 ++count;
800                 env = true; // Size change need not bother about closing env.
801         }
802         if (f.underbar() == ON) {
803                 os << '}';
804                 ++count;
805                 env = true; // Size change need not bother about closing env.
806         }
807         if (f.noun() == ON) {
808                 os << '}';
809                 ++count;
810                 env = true; // Size change need not bother about closing env.
811         }
812         if (f.size() != INHERIT_SIZE) {
813                 // We only have to close if only size changed
814                 if (!env) {
815                         os << '}';
816                         ++count;
817                 }
818         }
819         return count;
820 }
821
822
823 LColor::color LyXFont::realColor() const
824 {
825         if (latex() == ON)
826                 return LColor::latex;
827         if (color() == LColor::none)
828                 return LColor::foreground;
829         return color();
830 }
831
832
833 // Convert logical attributes to concrete shape attribute
834 LyXFont::FONT_SHAPE LyXFont::realShape() const
835 {
836         register FONT_SHAPE s = shape();
837
838         if (emph() == ON) {
839                 if (s == UP_SHAPE)
840                         s = ITALIC_SHAPE;
841                 else
842                         s = UP_SHAPE;
843         }
844         if (noun() == ON)
845                 s = SMALLCAPS_SHAPE;
846         return s;
847 }
848
849
850 XFontStruct * LyXFont::getXFontstruct() const
851 {
852         return fontloader.load(family(), series(), realShape(), size());
853 }
854
855
856 int LyXFont::maxAscent() const
857 {
858         return getXFontstruct()->ascent;
859 }
860
861
862 int LyXFont::maxDescent() const
863 {
864         return getXFontstruct()->descent;
865 }
866
867
868 int LyXFont::ascent(char c) const
869 {
870         XFontStruct * finfo = getXFontstruct();
871         unsigned int uc = static_cast<unsigned char>(c);
872         if (finfo->per_char
873             && uc >= finfo->min_char_or_byte2
874             && uc <= finfo->max_char_or_byte2) 
875                 return finfo->per_char[uc - finfo->min_char_or_byte2].ascent;
876         else
877                 return finfo->ascent;
878 }
879
880
881 int LyXFont::descent(char c) const
882 {
883         XFontStruct * finfo = getXFontstruct();
884         unsigned int uc = static_cast<unsigned char>(c);
885         if (finfo->per_char
886             && uc >= finfo->min_char_or_byte2
887             && uc <= finfo->max_char_or_byte2) 
888                 return finfo->per_char[uc - finfo->min_char_or_byte2].descent;
889         else
890                 return finfo->descent;
891 }
892
893
894 // Specialized after profiling. (Asger)
895 int LyXFont::width(char c) const
896 {
897         if (realShape() != LyXFont::SMALLCAPS_SHAPE){
898                 return XTextWidth(getXFontstruct(), &c, 1);
899         } else {
900                 return textWidth(&c, 1);
901         }
902 }
903
904
905 int LyXFont::lbearing(char c) const
906 {
907         XFontStruct * finfo = getXFontstruct();
908         unsigned int uc = static_cast<unsigned char>(c);
909         if (finfo->per_char
910             && uc >= finfo->min_char_or_byte2
911             && uc <= finfo->max_char_or_byte2) 
912                 return finfo->per_char[uc - finfo->min_char_or_byte2].lbearing;
913         else
914                 return 0;
915 }
916
917
918 int LyXFont::rbearing(char c) const
919 {
920         XFontStruct * finfo = getXFontstruct();
921         unsigned int uc = static_cast<unsigned char>(c);
922         if (finfo->per_char
923             && uc >= finfo->min_char_or_byte2
924             && uc <= finfo->max_char_or_byte2) 
925                 return finfo->per_char[uc - finfo->min_char_or_byte2].rbearing;
926         else
927                 return width(c);
928 }
929
930
931 int LyXFont::textWidth(char const * s, int n) const
932 {
933         if (realShape() != LyXFont::SMALLCAPS_SHAPE){
934                 return XTextWidth(getXFontstruct(), s, n);
935         } else {
936                 // emulate smallcaps since X doesn't support this
937                 unsigned int result = 0;
938                 char c;
939                 LyXFont smallfont = *this;
940                 smallfont.decSize();
941                 smallfont.decSize();
942                 smallfont.setShape(LyXFont::UP_SHAPE);
943                 for (int i = 0; i < n; ++i) {
944                         c = s[i];
945                         // when islower is a macro, the cast is needed (JMarc)
946                         if (islower(static_cast<unsigned char>(c))){
947                                 c = toupper(c);
948                                 result += XTextWidth(smallfont.getXFontstruct(), &c, 1);
949                         } else {
950                                 result += XTextWidth(getXFontstruct(), &c, 1);
951                         }
952                 }
953                 return result;
954         }
955 }
956
957
958 int LyXFont::stringWidth(string const & s) const
959 {
960         if (s.empty()) return 0;
961         return textWidth(s.c_str(), s.length());
962 }
963
964
965 int LyXFont::signedStringWidth(string const & s) const
966 {
967         if (s.empty()) return 0;
968         if (s.c_str()[0] == '-')
969                 return -textWidth(s.c_str()+1, s.length()-1);
970         else
971                 return textWidth(s.c_str(), s.length());
972 }
973
974
975 int LyXFont::drawText(char const * s, int n, Pixmap, 
976                       int, int x) const
977 {
978         if (realShape() != LyXFont::SMALLCAPS_SHAPE) {
979                 /* XDrawString(fl_display,
980                    pm,
981                    getGC(),
982                    x, baseline,
983                    s, n);
984                    XFlush(fl_display); */
985                 return XTextWidth(getXFontstruct(), s, n);
986
987         } else {
988                 // emulate smallcaps since X doesn't support this
989                 char c;
990                 int sx = x;
991                 LyXFont smallfont = *this;
992                 smallfont.decSize();
993                 smallfont.decSize();
994                 smallfont.setShape(LyXFont::UP_SHAPE);
995                 for (int i = 0; i < n; ++i) {
996                         c = s[i];
997                         if (islower(static_cast<unsigned char>(c))){
998                                 c = toupper(c);
999                                 /* XDrawString(fl_display,
1000                                    pm,
1001                                    smallfont.getGC(),
1002                                    x, baseline,
1003                                    &c, 1); */
1004                                 x += XTextWidth(smallfont.getXFontstruct(),
1005                                                 &c, 1);
1006                                 //XFlush(fl_display);
1007                         } else {
1008                                 /* XDrawString(fl_display,
1009                                    pm,
1010                                    getGC(),
1011                                    x, baseline,
1012                                    &c, 1);*/
1013                                 x += XTextWidth(getXFontstruct(), &c, 1);
1014                                 //XFlush(fl_display);
1015                         }
1016                 }
1017                 return x - sx;
1018         }
1019 }
1020
1021
1022 int LyXFont::drawString(string const & s, Pixmap pm, int baseline, int x) const
1023 {
1024         return drawText(s.c_str(), s.length(), pm, baseline, x);
1025 }
1026
1027
1028 bool LyXFont::equalExceptLatex(LyXFont const & f) const 
1029 {
1030         LyXFont f1 = *this;
1031         f1.setLatex(f.latex());
1032         return f1 == f;
1033 }
1034
1035
1036 LyXDirection LyXFont::getFontDirection() const
1037 {
1038         if (lyxrc->rtl_support 
1039             && direction() == LyXFont::RTL_DIR
1040             && latex() != LyXFont::ON)
1041                 return LYX_DIR_RIGHT_TO_LEFT;
1042         else
1043                 return LYX_DIR_LEFT_TO_RIGHT;
1044 }
1045
1046
1047 ostream & operator<<(ostream & o, LyXFont::FONT_MISC_STATE fms)
1048 {
1049         return o << int(fms);
1050 }