]> git.lyx.org Git - lyx.git/blob - src/FontInfo.cpp
dbd97eb19bc65c04a7c6bf2bb81236faf559ccd6
[lyx.git] / src / FontInfo.cpp
1 /**
2  * \file src/FontInfo.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Lars Gullik Bjønnes
7  * \author Jean-Marc Lasgouttes
8  * \author Angus Leeming
9  * \author André Pönitz
10  * \author Dekel Tsur
11  *
12  * Full author contact details are available in file CREDITS.
13  */
14
15 #include <config.h>
16
17 #include "FontInfo.h"
18
19 #include "support/debug.h"
20 #include "support/docstring.h"
21
22 using namespace std;
23
24 namespace lyx {
25
26 FontInfo const sane_font(
27         ROMAN_FAMILY,
28         MEDIUM_SERIES,
29         UP_SHAPE,
30         FONT_SIZE_NORMAL,
31         Color_none,
32         Color_background,
33         FONT_OFF,
34         FONT_OFF,
35         FONT_OFF,
36         FONT_OFF,
37         FONT_OFF,
38         FONT_OFF,
39         FONT_OFF);
40
41 FontInfo const inherit_font(
42         INHERIT_FAMILY,
43         INHERIT_SERIES,
44         INHERIT_SHAPE,
45         FONT_SIZE_INHERIT,
46         Color_inherit,
47         Color_inherit,
48         FONT_INHERIT,
49         FONT_INHERIT,
50         FONT_INHERIT,
51         FONT_INHERIT,
52         FONT_INHERIT,
53         FONT_INHERIT,
54         FONT_OFF);
55
56 FontInfo const ignore_font(
57         IGNORE_FAMILY,
58         IGNORE_SERIES,
59         IGNORE_SHAPE,
60         FONT_SIZE_IGNORE,
61         Color_ignore,
62         Color_ignore,
63         FONT_IGNORE,
64         FONT_IGNORE,
65         FONT_IGNORE,
66         FONT_IGNORE,
67         FONT_IGNORE,
68         FONT_IGNORE,
69         FONT_IGNORE);
70
71
72 FontInfo::FontInfo()
73 {
74         *this = sane_font;
75 }
76
77 /// Decreases font size_ by one
78 FontInfo & FontInfo::decSize()
79 {
80         switch (size_) {
81         case FONT_SIZE_HUGER:        size_ = FONT_SIZE_HUGE;     break;
82         case FONT_SIZE_HUGE:         size_ = FONT_SIZE_LARGEST;  break;
83         case FONT_SIZE_LARGEST:      size_ = FONT_SIZE_LARGER;   break;
84         case FONT_SIZE_LARGER:       size_ = FONT_SIZE_LARGE;    break;
85         case FONT_SIZE_LARGE:        size_ = FONT_SIZE_NORMAL;   break;
86         case FONT_SIZE_NORMAL:       size_ = FONT_SIZE_SMALL;    break;
87         case FONT_SIZE_SMALL:        size_ = FONT_SIZE_FOOTNOTE; break;
88         case FONT_SIZE_FOOTNOTE:     size_ = FONT_SIZE_SCRIPT;   break;
89         case FONT_SIZE_SCRIPT:       size_ = FONT_SIZE_TINY;     break;
90         case FONT_SIZE_TINY:         break;
91         case FONT_SIZE_INCREASE:
92                 LYXERR0("Can't FontInfo::decSize on FONT_SIZE_INCREASE");
93                 break;
94         case FONT_SIZE_DECREASE:
95                 LYXERR0("Can't FontInfo::decSize on FONT_SIZE_DECREASE");
96                 break;
97         case FONT_SIZE_INHERIT:
98                 LYXERR0("Can't FontInfo::decSize on FONT_SIZE_INHERIT");
99                 break;
100         case FONT_SIZE_IGNORE:
101                 LYXERR0("Can't FontInfo::decSize on FONT_SIZE_IGNORE");
102                 break;
103         }
104         return *this;
105 }
106
107
108 /// Increases font size_ by one
109 FontInfo & FontInfo::incSize()
110 {
111         switch (size_) {
112         case FONT_SIZE_HUGER:   break;
113         case FONT_SIZE_HUGE:         size_ = FONT_SIZE_HUGER;    break;
114         case FONT_SIZE_LARGEST:      size_ = FONT_SIZE_HUGE;     break;
115         case FONT_SIZE_LARGER:       size_ = FONT_SIZE_LARGEST;  break;
116         case FONT_SIZE_LARGE:        size_ = FONT_SIZE_LARGER;   break;
117         case FONT_SIZE_NORMAL:       size_ = FONT_SIZE_LARGE;    break;
118         case FONT_SIZE_SMALL:        size_ = FONT_SIZE_NORMAL;   break;
119         case FONT_SIZE_FOOTNOTE:     size_ = FONT_SIZE_SMALL;    break;
120         case FONT_SIZE_SCRIPT:       size_ = FONT_SIZE_FOOTNOTE; break;
121         case FONT_SIZE_TINY:         size_ = FONT_SIZE_SCRIPT;   break;
122         case FONT_SIZE_INCREASE:
123                 LYXERR0("Can't FontInfo::incSize on FONT_SIZE_INCREASE");
124                 break;
125         case FONT_SIZE_DECREASE:
126                 LYXERR0("Can't FontInfo::incSize on FONT_SIZE_DECREASE");
127                 break;
128         case FONT_SIZE_INHERIT:
129                 LYXERR0("Can't FontInfo::incSize on FONT_SIZE_INHERIT");
130                 break;
131         case FONT_SIZE_IGNORE:
132                 LYXERR0("Can't FontInfo::incSize on FONT_SIZE_IGNORE");
133                 break;
134         }
135         return *this;
136 }
137
138
139 /// Reduce font to fall back to template where possible
140 void FontInfo::reduce(FontInfo const & tmplt)
141 {
142         if (family_ == tmplt.family_)
143                 family_ = INHERIT_FAMILY;
144         if (series_ == tmplt.series_)
145                 series_ = INHERIT_SERIES;
146         if (shape_ == tmplt.shape_)
147                 shape_ = INHERIT_SHAPE;
148         if (size_ == tmplt.size_)
149                 size_ = FONT_SIZE_INHERIT;
150         if (emph_ == tmplt.emph_)
151                 emph_ = FONT_INHERIT;
152         if (underbar_ == tmplt.underbar_)
153                 underbar_ = FONT_INHERIT;
154         if (strikeout_ == tmplt.strikeout_)
155                 strikeout_ = FONT_INHERIT;
156         if (uuline_ == tmplt.uuline_)
157                 uuline_ = FONT_INHERIT;
158         if (uwave_ == tmplt.uwave_)
159                 uwave_ = FONT_INHERIT;
160         if (noun_ == tmplt.noun_)
161                 noun_ = FONT_INHERIT;
162         if (color_ == tmplt.color_)
163                 color_ = Color_inherit;
164         if (background_ == tmplt.background_)
165                 background_ = Color_inherit;
166 }
167
168
169 /// Realize font from a template
170 FontInfo & FontInfo::realize(FontInfo const & tmplt)
171 {
172         if ((*this) == inherit_font) {
173                 operator=(tmplt);
174                 return *this;
175         }
176
177         if (family_ == INHERIT_FAMILY)
178                 family_ = tmplt.family_;
179
180         if (series_ == INHERIT_SERIES)
181                 series_ = tmplt.series_;
182
183         if (shape_ == INHERIT_SHAPE)
184                 shape_ = tmplt.shape_;
185
186         if (size_ == FONT_SIZE_INHERIT)
187                 size_ = tmplt.size_;
188
189         if (emph_ == FONT_INHERIT)
190                 emph_ = tmplt.emph_;
191
192         if (underbar_ == FONT_INHERIT)
193                 underbar_ = tmplt.underbar_;
194
195         if (strikeout_ == FONT_INHERIT)
196                 strikeout_ = tmplt.strikeout_;
197
198         if (uuline_ == FONT_INHERIT)
199                 uuline_ = tmplt.uuline_;
200
201         if (uwave_ == FONT_INHERIT)
202                 uwave_ = tmplt.uwave_;
203
204         if (noun_ == FONT_INHERIT)
205                 noun_ = tmplt.noun_;
206
207         if (color_ == Color_inherit)
208                 color_ = tmplt.color_;
209
210         if (background_ == Color_inherit)
211                 background_ = tmplt.background_;
212
213         return *this;
214 }
215
216
217 /// Updates a misc setting according to request
218 static FontState setMisc(FontState newfont,
219         FontState org)
220 {
221         if (newfont == FONT_TOGGLE) {
222                 if (org == FONT_ON)
223                         return FONT_OFF;
224                 else if (org == FONT_OFF)
225                         return FONT_ON;
226                 else {
227                         LYXERR0("Font::setMisc: Need state"
228                                 " FONT_ON or FONT_OFF to toggle. Setting to FONT_ON");
229                         return FONT_ON;
230                 }
231         } else if (newfont == FONT_IGNORE)
232                 return org;
233         else
234                 return newfont;
235 }
236
237 /// Updates font settings according to request
238 void FontInfo::update(FontInfo const & newfont, bool toggleall)
239 {
240         if (newfont.family_ == family_ && toggleall)
241                 setFamily(INHERIT_FAMILY); // toggle 'back'
242         else if (newfont.family_ != IGNORE_FAMILY)
243                 setFamily(newfont.family_);
244         // else it's IGNORE_SHAPE
245
246         // "Old" behaviour: "Setting" bold will toggle bold on/off.
247         switch (newfont.series_) {
248         case BOLD_SERIES:
249                 // We toggle...
250                 if (series_ == BOLD_SERIES && toggleall)
251                         setSeries(MEDIUM_SERIES);
252                 else
253                         setSeries(BOLD_SERIES);
254                 break;
255         case MEDIUM_SERIES:
256         case INHERIT_SERIES:
257                 setSeries(newfont.series_);
258                 break;
259         case IGNORE_SERIES:
260                 break;
261         }
262
263         if (newfont.shape_ == shape_ && toggleall)
264                 shape_ = INHERIT_SHAPE; // toggle 'back'
265         else if (newfont.shape_ != IGNORE_SHAPE)
266                 shape_ = newfont.shape_;
267         // else it's IGNORE_SHAPE
268
269         if (newfont.size_ != FONT_SIZE_IGNORE) {
270                 if (newfont.size_ == FONT_SIZE_INCREASE)
271                         incSize();
272                 else if (newfont.size_ == FONT_SIZE_DECREASE)
273                         decSize();
274                 else
275                         size_ = newfont.size_;
276         }
277
278         setEmph(setMisc(newfont.emph_, emph_));
279         setUnderbar(setMisc(newfont.underbar_, underbar_));
280         setStrikeout(setMisc(newfont.strikeout_, strikeout_));
281         setUuline(setMisc(newfont.uuline_, uuline_));
282         setUwave(setMisc(newfont.uwave_, uwave_));
283         setNoun(setMisc(newfont.noun_, noun_));
284         setNumber(setMisc(newfont.number_, number_));
285
286         if (newfont.color_ == color_ && toggleall)
287                 setColor(Color_inherit); // toggle 'back'
288         else if (newfont.color_ != Color_ignore)
289                 setColor(newfont.color_);
290
291         if (newfont.background_ == background_ && toggleall)
292                 setBackground(Color_inherit); // toggle 'back'
293         else if (newfont.background_ != Color_ignore)
294                 setBackground(newfont.background_);
295 }
296
297 /// Is font resolved?
298 bool FontInfo::resolved() const
299 {
300         return (family_ != INHERIT_FAMILY && series_ != INHERIT_SERIES
301                 && shape_ != INHERIT_SHAPE && size_ != FONT_SIZE_INHERIT
302                 && emph_ != FONT_INHERIT && underbar_ != FONT_INHERIT
303                 && uuline_ != FONT_INHERIT && uwave_ != FONT_INHERIT
304                 && strikeout_ != FONT_INHERIT && noun_ != FONT_INHERIT
305                 && color_ != Color_inherit
306                 && background_ != Color_inherit);
307 }
308
309
310 Color FontInfo::realColor() const
311 {
312         if (paint_color_ != Color_none)
313                 return paint_color_;
314         if (color_ == Color_none)
315                 return Color_foreground;
316         return color_;
317 }
318
319
320 namespace {
321
322         void appendSep(string & s1, string const & s2) {
323                 if (s2.empty()) 
324                         return;
325                 s1 += s1.empty() ? "" : "\n";
326                 s1 += s2;
327         }
328
329
330         string makeCSSTag(string const & key, string const & val)
331         {
332                 return key + ": " + val + ";";
333         }
334
335
336         string getFamilyCSS(FontFamily const & f)
337         {
338                 switch (f) {
339                 case ROMAN_FAMILY: return "serif";
340                 case SANS_FAMILY: return "sans-serif";
341                 case TYPEWRITER_FAMILY: return "monospace";
342                 case INHERIT_FAMILY: return "inherit";
343                 default: break;
344                 }
345                 return "";
346         }
347
348
349         string getSeriesCSS(FontSeries const & s)
350         {
351                 switch (s) {
352                 case MEDIUM_SERIES: return "normal";
353                 case BOLD_SERIES: return "bold";
354                 case INHERIT_SERIES: return "inherit";
355                 default: break;
356                 }
357                 return "";
358         }
359
360
361         string getShapeCSS(FontShape const & s)
362         {
363                 string fs = "normal";
364                 string fv = "normal";
365                 switch (s) {
366                 case UP_SHAPE: break;
367                 case ITALIC_SHAPE: fs = "italic"; break;
368                 case SLANTED_SHAPE: fs = "oblique"; break;
369                 case SMALLCAPS_SHAPE: fv = "small-caps"; break;
370                 case INHERIT_SHAPE: fs = "inherit"; fv = "inherit"; break;
371                 case IGNORE_SHAPE: fs = ""; fv = ""; break;
372                 }
373                 string retval;
374                 if (!fs.empty())
375                         appendSep(retval, makeCSSTag("font-style", fs));
376                 if (!fv.empty())
377                         appendSep(retval, makeCSSTag("font-variant", fv));
378                 return retval;
379         }
380
381
382         string getSizeCSS(FontSize const & s)
383         {
384                 switch (s) {
385                 case FONT_SIZE_TINY: return "xx-small";
386                 case FONT_SIZE_SCRIPT: return "x-small";
387                 case FONT_SIZE_FOOTNOTE: 
388                 case FONT_SIZE_SMALL: return "small";
389                 case FONT_SIZE_NORMAL: return "medium";
390                 case FONT_SIZE_LARGE: return "large";
391                 case FONT_SIZE_LARGER: 
392                 case FONT_SIZE_LARGEST: return "x-large";
393                 case FONT_SIZE_HUGE: 
394                 case FONT_SIZE_HUGER: return "xx-large";
395                 case FONT_SIZE_INCREASE: return "larger";
396                 case FONT_SIZE_DECREASE: return "smaller";
397                 case FONT_SIZE_INHERIT: return "inherit";
398                 case FONT_SIZE_IGNORE: return "";
399                 }       
400                 // squash warning
401                 return "";
402         }
403         
404 } // namespace anonymous
405
406
407 // FIXME This does not yet handle color
408 docstring FontInfo::asCSS() const 
409 {
410         string retval;
411         string tmp = getFamilyCSS(family_);
412         if (!tmp.empty())
413                 appendSep(retval, makeCSSTag("font-family", tmp));
414         tmp = getSeriesCSS(series_);
415         if (!tmp.empty())
416                 appendSep(retval, makeCSSTag("font-series", tmp));
417         appendSep(retval, getShapeCSS(shape_));
418         tmp = getSizeCSS(size_);
419         if (!tmp.empty())
420                 appendSep(retval, makeCSSTag("font-size", tmp));
421         return from_ascii(retval);      
422 }
423
424 } // namespace lyx