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