]> git.lyx.org Git - lyx.git/blob - src/mathed/math_support.C
small font stuff
[lyx.git] / src / mathed / math_support.C
1 #include <config.h>
2
3 #include <map>
4
5 #include "math_support.h"
6 #include "lyxfont.h"
7 #include "frontends/font_loader.h"
8 #include "frontends/font_metrics.h"
9 #include "math_cursor.h"
10 #include "math_defs.h"
11 #include "math_inset.h"
12 #include "math_parser.h"
13 #include "frontends/Painter.h"
14 #include "debug.h"
15 #include "commandtags.h"
16
17 using std::map;
18 using std::endl;
19 using std::max;
20
21
22 ///
23 class Matrix {
24 public:
25         ///
26         Matrix(int, double, double);
27         ///
28         void transform(double &, double &);
29 private:
30         ///
31         double m_[2][2];
32 };
33
34
35 Matrix::Matrix(int code, double x, double y)
36 {
37         double const cs = (code & 1) ? 0 : (1 - code);
38         double const sn = (code & 1) ? (2 - code) : 0;
39         m_[0][0] =  cs * x;
40         m_[0][1] =  sn * x;
41         m_[1][0] = -sn * y;
42         m_[1][1] =  cs * y;
43 }
44
45
46 void Matrix::transform(double & x, double & y)
47 {
48         double xx = m_[0][0] * x + m_[0][1] * y;
49         double yy = m_[1][0] * x + m_[1][1] * y;
50         x = xx;
51         y = yy;
52 }
53
54
55
56 namespace {
57
58 /*
59  * Internal struct of a drawing: code n x1 y1 ... xn yn, where code is:
60  * 0 = end, 1 = line, 2 = polyline, 3 = square line, 4= square polyline
61  */
62
63
64 double const parenthHigh[] = {
65         2, 13,
66         0.9840, 0.0014, 0.7143, 0.0323, 0.4603, 0.0772,
67         0.2540, 0.1278, 0.1746, 0.1966, 0.0952, 0.3300,
68         0.0950, 0.5000, 0.0952, 0.6700, 0.1746, 0.8034,
69         0.2540, 0.8722, 0.4603, 0.9228, 0.7143, 0.9677,
70         0.9840, 0.9986,
71         0
72 };
73
74
75 double const parenth[] = {
76         2, 13,
77         0.9930, 0.0071, 0.7324, 0.0578, 0.5141, 0.1126,
78         0.3380, 0.1714, 0.2183, 0.2333, 0.0634, 0.3621,
79         0.0141, 0.5000, 0.0563, 0.6369, 0.2113, 0.7647,
80         0.3310, 0.8276, 0.5070, 0.8864, 0.7254, 0.9412,
81         0.9930, 0.9919,
82         0
83 };
84
85
86 double const brace[] = {
87         2, 21,
88         0.9492, 0.0020, 0.9379, 0.0020, 0.7458, 0.0243,
89         0.5819, 0.0527, 0.4859, 0.0892, 0.4463, 0.1278,
90         0.4463, 0.3732, 0.4011, 0.4199, 0.2712, 0.4615,
91         0.0734, 0.4919, 0.0113, 0.5000, 0.0734, 0.5081,
92         0.2712, 0.5385, 0.4011, 0.5801, 0.4463, 0.6268,
93         0.4463, 0.8722, 0.4859, 0.9108, 0.5819, 0.9473,
94         0.7458, 0.9757, 0.9379, 0.9980, 0.9492, 0.9980,
95         0
96 };
97
98
99 double const arrow[] = {
100         4, 7,
101         0.0150, 0.7500, 0.2000, 0.6000, 0.3500, 0.3500,
102         0.5000, 0.0500, 0.6500, 0.3500, 0.8000, 0.6000,
103         0.9500, 0.7500,
104         3, 0.5000, 0.1500, 0.5000, 0.9500,
105         0
106 };
107
108
109 double const Arrow[] = {
110         4, 7,
111         0.0150, 0.7500, 0.2000, 0.6000, 0.3500, 0.3500,
112         0.5000, 0.0500, 0.6500, 0.3500, 0.8000, 0.6000,
113         0.9500, 0.7500,
114         3, 0.3500, 0.5000, 0.3500, 0.9500,
115         3, 0.6500, 0.5000, 0.6500, 0.9500,
116         0
117 };
118
119
120 double const udarrow[] = {
121         2, 3,
122         0.015, 0.25,  0.5, 0.05, 0.95, 0.25,
123         2, 3,
124         0.015, 0.75,  0.5, 0.95, 0.95, 0.75,
125         1, 0.5, 0.2,  0.5, 0.8,
126         0
127 };
128
129
130 double const Udarrow[] = {
131         2, 3,
132         0.015, 0.25,  0.5, 0.05, 0.95, 0.25,
133         2, 3,
134         0.015, 0.75,  0.5, 0.95, 0.95, 0.75,
135         1, 0.35, 0.2, 0.35, 0.8,
136         1, 0.65, 0.2, 0.65, 0.8,
137         0
138 };
139
140
141 double const brack[] = {
142         2, 4,
143         0.95, 0.05,  0.05, 0.05,  0.05, 0.95,  0.95, 0.95,
144         0
145 };
146
147
148 double const corner[] = {
149         2, 3,
150         0.95, 0.05,  0.05, 0.05,  0.05, 0.95,
151         0
152 };
153
154
155 double const angle[] = {
156         2, 3,
157         1, 0,  0.05, 0.5,  1, 1,
158         0
159 };
160
161
162 double const slash[] = {
163         1, 0.95, 0.05, 0.05, 0.95,
164         0
165 };
166
167
168 double const hline[] = {
169         1, 0.00, 0.5, 1.0, 0.5,
170         0
171 };
172
173
174 double const ddot[] = {
175         1, 0.2, 0.5,  0.3, 0.5,
176         1, 0.7, 0.5,  0.8, 0.5,
177         0
178 };
179
180
181 double const dddot[] = {
182         1, 0.1, 0.5,  0.2, 0.5,
183         1, 0.45, 0.5, 0.55, 0.5,
184         1, 0.8, 0.5,  0.9, 0.5,
185         0
186 };
187
188
189 double const hline3[] = {
190         1, 0.1,   0,  0.15,  0,
191         1, 0.475, 0,  0.525, 0,
192         1, 0.85,  0,  0.9,   0,
193         0
194 };
195
196
197 double const dline3[] = {
198         1, 0.1,   0.1,   0.15,  0.15,
199         1, 0.475, 0.475, 0.525, 0.525,
200         1, 0.85,  0.85,  0.9,   0.9,
201         0
202 };
203
204
205 double const hlinesmall[] = {
206         1, 0.4, 0.5, 0.6, 0.5,
207         0
208 };
209
210
211 double const ring[] = {
212         2, 5,
213         0.5, 0.8,  0.8, 0.5,  0.5, 0.2,  0.2, 0.5,  0.5, 0.8,
214         0
215 };
216
217
218 double const vert[] = {
219         1, 0.5, 0.05,  0.5, 0.95,
220         0
221 };
222
223
224 double const  Vert[] = {
225         1, 0.3, 0.05,  0.3, 0.95,
226         1, 0.7, 0.05,  0.7, 0.95,
227         0
228 };
229
230
231 double const tilde[] = {
232         2, 4,
233         0.05, 0.8,  0.25, 0.2,  0.75, 0.8,  0.95, 0.2,
234         0
235 };
236
237
238 struct deco_struct {
239         double const * data;
240         int angle;
241 };
242
243 struct named_deco_struct {
244         char const * name;
245         double const * data;
246         int angle;
247 };
248
249 named_deco_struct deco_table[] = {
250         // Decorations
251         {"widehat",             angle,    3 },
252         {"widetilde",           tilde,    0 },
253         {"underbar",            hline,    0 },
254         {"underline",           hline,    0 },
255         {"overline",            hline,    0 },
256         {"underbrace",          brace,    1 },
257         {"overbrace",           brace,    3 },
258         {"overleftarrow",       arrow,    1 },
259         {"overrightarrow",      arrow,    3 },
260         {"overleftrightarrow",  udarrow,  1 },
261         {"xleftarrow",          arrow,    1 },
262         {"xrightarrow",         arrow,    3 },
263         {"underleftarrow",      arrow,    1 },
264         {"underrightarrow",     arrow,    3 },
265         {"underleftrightarrow", udarrow,  1 },
266
267         // Delimiters
268         {"(",              parenth,    0 },
269         {")",              parenth,    2 },
270         {"{",              brace,      0 },
271         {"}",              brace,      2 },
272         {"[",              brack,      0 },
273         {"]",              brack,      2 },
274         {"|",              vert,       0 },
275         {"/",              slash,      0 },
276         {"vert",           vert,       0 },
277         {"Vert",           Vert,       0 },
278         {"'",              slash,      1 },
279         {"backslash",      slash,      1 },
280         {"langle",         angle,      0 },
281         {"lceil",          corner,     0 },
282         {"lfloor",         corner,     1 },
283         {"rangle",         angle,      2 },
284         {"rceil",          corner,     3 },
285         {"rfloor",         corner,     2 },
286         {"downarrow",      arrow,      2 },
287         {"Downarrow",      Arrow,      2 },
288         {"uparrow",        arrow,      0 },
289         {"Uparrow",        Arrow,      0 },
290         {"updownarrow",    udarrow,    0 },
291         {"Updownarrow",    Udarrow,    0 },
292
293         // Accents
294         {"ddot",           ddot,       0 },
295         {"dddot",          dddot,      0 },
296         {"hat",            angle,      3 },
297         {"grave",          slash,      1 },
298         {"acute",          slash,      0 },
299         {"tilde",          tilde,      0 },
300         {"bar",            hline,      0 },
301         {"dot",            hlinesmall, 0 },
302         {"check",          angle,      1 },
303         {"breve",          parenth,    1 },
304         {"vec",            arrow,      3 },
305         {"not",            slash,      0 },
306         {"mathring",       ring,       0 },
307
308         // Dots
309         {"ldots",          hline3,     0 },
310         {"cdots",          hline3,     0 },
311         {"vdots",          hline3,     1 },
312         {"ddots",          dline3,     0 },
313         {"dotsb",          hline3,     0 },
314         {"dotsc",          hline3,     0 },
315         {"dotsi",          hline3,     0 },
316         {"dotsm",          hline3,     0 },
317         {"dotso",          hline3,     0 }
318 };
319
320
321 map<string, deco_struct> deco_list;
322
323 // sort the table on startup
324 struct init_deco_table {
325         init_deco_table() {
326                 unsigned const n = sizeof(deco_table) / sizeof(deco_table[0]);
327                 for (named_deco_struct * p = deco_table; p != deco_table + n; ++p) {
328                         deco_struct d;
329                         d.data  = p->data;
330                         d.angle = p->angle;
331                         deco_list[p->name]= d;
332                 }
333         }
334 };
335
336 static init_deco_table dummy;
337
338
339 deco_struct const * search_deco(string const & name)
340 {
341         map<string, deco_struct>::const_iterator p = deco_list.find(name);
342         return (p == deco_list.end()) ? 0 : &(p->second);
343 }
344
345
346 } // namespace anon
347
348
349 void mathed_char_dim(LyXFont const & font,
350         unsigned char c, int & asc, int & des, int & wid)
351 {
352         des = font_metrics::descent(c, font);
353         asc = font_metrics::ascent(c, font);
354         wid = mathed_char_width(font, c);
355 }
356
357
358 int mathed_char_ascent(LyXFont const & font, unsigned char c)
359 {
360         return font_metrics::ascent(c, font);
361 }
362
363
364 int mathed_char_descent(LyXFont const & font, unsigned char c)
365 {
366         return font_metrics::descent(c, font);
367 }
368
369
370 int mathed_char_width(LyXFont const & font, unsigned char c)
371 {
372         return font_metrics::width(c, font);
373 }
374
375
376 void mathed_string_dim(LyXFont const & font,
377         string const & s, int & asc, int & des, int & wid)
378 {
379         asc = des = 0;
380         for (string::const_iterator it = s.begin(); it != s.end(); ++it) {
381                 des = max(des, font_metrics::descent(*it, font));
382                 asc = max(asc, font_metrics::ascent(*it, font));
383         }
384         wid = font_metrics::width(s, font);
385 }
386
387
388 int mathed_string_width(LyXFont const & font, string const & s)
389 {
390         return font_metrics::width(s, font);
391 }
392
393
394 int mathed_string_ascent(LyXFont const & font, string const & s)
395 {
396         int asc = 0;
397         for (string::const_iterator it = s.begin(); it != s.end(); ++it)
398                 asc = max(asc, font_metrics::ascent(*it, font));
399         return asc;
400 }
401
402
403 int mathed_string_descent(LyXFont const & font, string const & s)
404 {
405         int des = 0;
406         for (string::const_iterator it = s.begin(); it != s.end(); ++it)
407                 des = max(des, font_metrics::descent(*it, font));
408         return des;
409 }
410
411
412
413 void mathed_draw_deco(MathPainterInfo & pain, int x, int y, int w, int h,
414         const string & name)
415 {
416         if (name == ".") {
417                 pain.pain.line(x + w/2, y, x + w/2, y + h,
418                           LColor::mathcursor, Painter::line_onoffdash);
419                 return;
420         }
421
422         deco_struct const * mds = search_deco(name);
423         if (!mds) {
424                 lyxerr << "Deco was not found. Programming error?\n";
425                 lyxerr << "name: '" << name << "'\n";
426                 return;
427         }
428
429         int const n = (w < h) ? w : h;
430         int const r = mds->angle;
431         double const * d = mds->data;
432
433         if (h > 70 && (name == "(" || name == ")"))
434                 d = parenthHigh;
435
436         Matrix mt(r, w, h);
437         Matrix sqmt(r, n, n);
438
439         if (r > 0 && r < 3)
440                 y += h;
441
442         if (r >= 2)
443                 x += w;
444
445         for (int i = 0; d[i]; ) {
446                 int code = int(d[i++]);
447                 if (code & 1) {  // code == 1 || code == 3
448                         double xx = d[i++];
449                         double yy = d[i++];
450                         double x2 = d[i++];
451                         double y2 = d[i++];
452                         if (code == 3)
453                                 sqmt.transform(xx, yy);
454                         else
455                                 mt.transform(xx, yy);
456                         mt.transform(x2, y2);
457                         pain.pain.line(
458                                 x + int(xx + 0.5), y + int(yy + 0.5),
459                                 x + int(x2 + 0.5), y + int(y2 + 0.5),
460                                 LColor::math);
461                 }       else {
462                         int xp[32];
463                         int yp[32];
464                         int const n = int(d[i++]);
465                         for (int j = 0; j < n; ++j) {
466                                 double xx = d[i++];
467                                 double yy = d[i++];
468 //           lyxerr << " " << xx << " " << yy << " ";
469                                 if (code == 4)
470                                         sqmt.transform(xx, yy);
471                                 else
472                                         mt.transform(xx, yy);
473                                 xp[j] = x + int(xx + 0.5);
474                                 yp[j] = y + int(yy + 0.5);
475                                 //  lyxerr << "P[" << j " " << xx << " " << yy << " " << x << " " << y << "]";
476                         }
477                         pain.pain.lines(xp, yp, n, LColor::math);
478                 }
479         }
480 }
481
482
483 void mathed_draw_framebox(MathPainterInfo & pain, int x, int y, MathInset const * p)
484 {
485         if (mathcursor && mathcursor->isInside(p))
486                 pain.pain.rectangle(x, y - p->ascent(), p->width(), p->height(),
487                         LColor::mathframe);
488 }
489
490
491 // In the future maybe we use a better fonts renderer
492 void drawStr(MathPainterInfo & pain, LyXFont const & font,
493         int x, int y, string const & str)
494 {
495         pain.pain.text(x, y, str, font);
496 }
497
498
499 void drawStrRed(MathPainterInfo & pi, int x, int y, string const & str)
500 {
501         LyXFont f = pi.base.font;
502         f.setColor(LColor::latex);
503         pi.pain.text(x, y, str, f);
504 }
505
506
507 void drawStrBlack(MathPainterInfo & pi, int x, int y, string const & str)
508 {
509         LyXFont f = pi.base.font;
510         f.setColor(LColor::black);
511         pi.pain.text(x, y, str, f);
512 }
513
514
515 void drawChar(MathPainterInfo & pi, LyXFont const & font, int x, int y, char c)
516 {
517         pi.pain.text(x, y, c, font);
518 }
519
520
521 void math_font_max_dim(LyXFont const & font, int & asc, int & des)
522 {
523         asc = font_metrics::maxAscent(font);
524         des = font_metrics::maxDescent(font);
525 }
526
527
528 string convertDelimToLatexName(string const & name)
529 {
530         if (name == "(")
531                 return name;
532         if (name == "[")
533                 return name;
534         if (name == ".")
535                 return name;
536         if (name == ")")
537                 return name;
538         if (name == "]")
539                 return name;
540         if (name == "/")
541                 return name;
542         if (name == "|")
543                 return name;
544         return "\\" + name + " ";
545 }
546
547
548
549
550 struct fontinfo {
551         string cmd_;
552         LyXFont::FONT_FAMILY family_;
553         LyXFont::FONT_SERIES series_;
554         LyXFont::FONT_SHAPE  shape_;
555         LColor::color        color_;
556 };
557
558
559 LyXFont::FONT_FAMILY const def_family = LyXFont::INHERIT_FAMILY;
560 LyXFont::FONT_SERIES const def_series = LyXFont::INHERIT_SERIES;
561 LyXFont::FONT_SHAPE  const def_shape  = LyXFont::INHERIT_SHAPE; 
562
563
564
565 fontinfo fontinfos[] = {
566         {"cmex",   LyXFont::CMEX_FAMILY, def_series, def_shape, LColor::math},
567         {"cmm",    LyXFont::CMM_FAMILY, def_series, def_shape, LColor::math},
568         {"cmr",    LyXFont::CMR_FAMILY, def_series, def_shape, LColor::math},
569         {"cmsy",   LyXFont::CMSY_FAMILY, def_series, def_shape, LColor::math},
570         {"eufrak", LyXFont::EUFRAK_FAMILY, def_series, def_shape, LColor::math},
571         {"mathbf", def_family, LyXFont::BOLD_SERIES, def_shape, LColor::math},
572         {"mathcal",LyXFont::CMSY_FAMILY, def_series, def_shape, LColor::math},
573         {"mathnormal", def_family,def_series, LyXFont::UP_SHAPE, LColor::math},
574         {"mathrm", LyXFont::ROMAN_FAMILY, def_series, def_shape, LColor::math},
575         {"mathsf", LyXFont::SANS_FAMILY, def_series, def_shape, LColor::math},
576         {"msa",    LyXFont::MSA_FAMILY, def_series, def_shape, LColor::math},
577         {"msb",    LyXFont::MSB_FAMILY, def_series, def_shape, LColor::math},
578         {"textbf", def_family, LyXFont::BOLD_SERIES, def_shape, LColor::black},
579         {"textit", def_family, def_series, LyXFont::ITALIC_SHAPE, LColor::black},
580         {"textmd", def_family, LyXFont::MEDIUM_SERIES, def_shape, LColor::black},
581         {"textnormal", def_family, def_series, LyXFont::UP_SHAPE, LColor::black},
582         {"textrm", LyXFont::ROMAN_FAMILY, def_series,LyXFont::UP_SHAPE,LColor::black},
583         {"textsc", def_family, def_series, LyXFont::SMALLCAPS_SHAPE, LColor::black},
584         {"textsf", LyXFont::SANS_FAMILY, def_series, def_shape, LColor::black},
585         {"textsl", def_family, def_series, LyXFont::SLANTED_SHAPE, LColor::black},
586         {"texttt", LyXFont::TYPEWRITER_FAMILY, def_series, def_shape, LColor::black},
587         {"textup", def_family, def_series, LyXFont::UP_SHAPE, LColor::black},
588
589         {"lyxtex", def_family, def_series, def_shape, LColor::latex},
590         {"lyxsymbol", LyXFont::SYMBOL_FAMILY, def_series, def_shape, LColor::math},
591         {"lyxitsymbol", LyXFont::SYMBOL_FAMILY, def_series, LyXFont::ITALIC_SHAPE, LColor::math},
592 };
593
594
595 fontinfo * searchFont(string const & name)
596 {
597         int const n = sizeof(fontinfos) / sizeof(fontinfo);
598         //lyxerr << "searching font '" << name << "'\n"; 
599         for (int i = 0; i < n; ++i)
600                 if (fontinfos[i].cmd_ == name) {
601                         //lyxerr << "found '" << i << "'\n"; 
602                         return fontinfos + i;
603                 }
604         return searchFont("mathnormal");
605 }
606
607
608 void augmentFont(LyXFont & font, string const & name)
609 {
610         static bool initialized = false;
611         
612         if (!initialized) {
613                 initialized = true;
614
615                 LyXFont f1;
616                 augmentFont(f1, "msb");
617                 if (!fontloader.available(f1)) {
618                         lyxerr << "faking msb\n";
619                         fontinfo * info = searchFont("msb");
620                         info->family_ = LyXFont::TYPEWRITER_FAMILY;
621                         info->series_ = LyXFont::BOLD_SERIES;
622                 }
623
624                 LyXFont f2;
625                 augmentFont(f2, "msex");
626                 if (!fontloader.available(f2)) {
627                         lyxerr << "faking msex\n";
628                         fontinfo * info = searchFont("msex");
629                         info->family_ = LyXFont::SANS_FAMILY;
630                         info->series_ = LyXFont::BOLD_SERIES;
631                         info->shape_  = LyXFont::ITALIC_SHAPE;
632                 }
633
634                 //{"fakebb", LyXFont::TYPEWRITER_FAMILY, LyXFont::BOLD_SERIES,
635                 //      LyXFont::UP_SHAPE, LColor::math},
636                 //{"fakecal", LyXFont::SANS_FAMILY, LyXFont::MEDIUM_SERIES,
637                 //      LyXFont::ITALIC_SHAPE, LColor::math},
638                 //{"fakefrak", LyXFont::SANS_FAMILY, LyXFont::BOLD_SERIES,
639                 //      LyXFont::ITALIC_SHAPE, LColor::math}
640
641         }
642
643
644         fontinfo * info = searchFont(name);
645         if (info->family_ != def_family)
646                 font.setFamily(info->family_);
647
648         if (info->series_ != def_series)
649                 font.setSeries(info->series_);
650
651         if (info->shape_ != def_shape)
652                 font.setShape(info->shape_);
653
654         if (info->color_ != LColor::none)
655                 font.setColor(info->color_);
656 }
657
658
659 bool math_font_available(string const & /*name*/)
660 {
661         return true;
662 }