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