]> git.lyx.org Git - lyx.git/blob - src/mathed/math_support.C
fonts as insets
[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(x + int(xx), y + int(yy), x + int(x2), y + int(y2),
458                                         LColor::math);
459                 }       else {
460                         int xp[32];
461                         int yp[32];
462                         int const n = int(d[i++]);
463                         for (int j = 0; j < n; ++j) {
464                                 double xx = d[i++];
465                                 double yy = d[i++];
466 //           lyxerr << " " << xx << " " << yy << " ";
467                                 if (code == 4)
468                                         sqmt.transform(xx, yy);
469                                 else
470                                         mt.transform(xx, yy);
471                                 xp[j] = x + int(xx);
472                                 yp[j] = y + int(yy);
473                                 //  lyxerr << "P[" << j " " << xx << " " << yy << " " << x << " " << y << "]";
474                         }
475                         pain.pain.lines(xp, yp, n, LColor::math);
476                 }
477         }
478 }
479
480
481 void mathed_draw_framebox(MathPainterInfo & pain, int x, int y, MathInset const * p)
482 {
483         if (mathcursor && mathcursor->isInside(p))
484                 pain.pain.rectangle(x, y - p->ascent(), p->width(), p->height(),
485                         LColor::mathframe);
486 }
487
488
489 // In the future maybe we use a better fonts renderer
490 void drawStr(MathPainterInfo & pain, LyXFont const & font,
491         int x, int y, string const & str)
492 {
493         pain.pain.text(x, y, str, font);
494 }
495
496
497 void drawStrRed(MathPainterInfo & pi, int x, int y, string const & str)
498 {
499         LyXFont f = pi.base.font;
500         f.setColor(LColor::latex);
501         pi.pain.text(x, y, str, f);
502 }
503
504
505 void drawStrBlack(MathPainterInfo & pi, int x, int y, string const & str)
506 {
507         LyXFont f = pi.base.font;
508         f.setColor(LColor::black);
509         pi.pain.text(x, y, str, f);
510 }
511
512
513 void drawChar(MathPainterInfo & pi, LyXFont const & font, int x, int y, char c)
514 {
515         pi.pain.text(x, y, c, font);
516 }
517
518
519 void math_font_max_dim(LyXFont const & font, int & asc, int & des)
520 {
521         asc = font_metrics::maxAscent(font);
522         des = font_metrics::maxDescent(font);
523 }
524
525
526 string convertDelimToLatexName(string const & name)
527 {
528         if (name == "(")
529                 return name;
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         return "\\" + name + " ";
543 }
544
545
546
547
548 struct fontinfo {
549         string cmd_;
550         LyXFont::FONT_FAMILY family_;
551         LyXFont::FONT_SERIES series_;
552         LyXFont::FONT_SHAPE  shape_;
553         LColor::color        color_;
554 };
555
556
557 LyXFont::FONT_FAMILY const def_family = LyXFont::INHERIT_FAMILY;
558 LyXFont::FONT_SERIES const def_series = LyXFont::INHERIT_SERIES;
559 LyXFont::FONT_SHAPE  const def_shape  = LyXFont::INHERIT_SHAPE; 
560
561
562
563 fontinfo fontinfos[] = {
564         {"cmex",   LyXFont::CMEX_FAMILY, def_series, def_shape, LColor::math},
565         {"cmm",    LyXFont::CMM_FAMILY, def_series, def_shape, LColor::math},
566         {"cmr",    LyXFont::CMR_FAMILY, def_series, def_shape, LColor::math},
567         {"cmsy",   LyXFont::CMSY_FAMILY, def_series, def_shape, LColor::math},
568         {"eufrak", LyXFont::EUFRAK_FAMILY, def_series, def_shape, LColor::math},
569         {"mathbf", def_family, LyXFont::BOLD_SERIES, def_shape, LColor::math},
570         {"mathcal",LyXFont::CMSY_FAMILY, def_series, def_shape, LColor::math},
571         {"mathnormal", def_family,def_series, def_shape, LColor::math},
572         {"mathrm", LyXFont::ROMAN_FAMILY, def_series, def_shape, LColor::math},
573         {"mathsf", LyXFont::SANS_FAMILY, def_series, def_shape, LColor::math},
574         {"msa",    LyXFont::MSA_FAMILY, def_series, def_shape, LColor::math},
575         {"msb",    LyXFont::MSB_FAMILY, def_series, def_shape, LColor::math},
576         {"textbf", def_family, LyXFont::BOLD_SERIES, def_shape, LColor::black},
577         {"textit", def_family, def_series, LyXFont::ITALIC_SHAPE, LColor::black},
578         {"textmd", def_family, LyXFont::MEDIUM_SERIES, def_shape, LColor::black},
579         {"textnormal", def_family, def_series, def_shape, LColor::black},
580         {"textrm", LyXFont::ROMAN_FAMILY, def_series, def_shape, LColor::black},
581         {"textsc", def_family, def_series, LyXFont::SMALLCAPS_SHAPE, LColor::black},
582         {"textsf", LyXFont::SANS_FAMILY, def_series, def_shape, LColor::black},
583         {"textsl", def_family, def_series, LyXFont::SLANTED_SHAPE, LColor::black},
584         {"texttt", LyXFont::TYPEWRITER_FAMILY, def_series, def_shape, LColor::black},
585         {"textup", def_family, def_series, LyXFont::UP_SHAPE, LColor::black},
586
587         {"lyxtex", def_family, def_series, def_shape, LColor::latex},
588         {"lyxsymbol", LyXFont::SYMBOL_FAMILY, def_series, def_shape, LColor::math},
589         {"lyxitsymbol", LyXFont::SYMBOL_FAMILY, def_series, LyXFont::ITALIC_SHAPE, LColor::math},
590 };
591
592
593 fontinfo * searchFont(string const & name)
594 {
595         int const n = sizeof(fontinfos) / sizeof(fontinfo);
596         //lyxerr << "searching font '" << name << "'\n"; 
597         for (int i = 0; i < n; ++i)
598                 if (fontinfos[i].cmd_ == name) {
599                         //lyxerr << "found '" << i << "'\n"; 
600                         return fontinfos + i;
601                 }
602         return searchFont("mathnormal");
603 }
604
605
606 void augmentFont(LyXFont & font, string const & name)
607 {
608         static bool initialized = false;
609         
610         if (!initialized) {
611                 initialized = true;
612
613                 LyXFont f1;
614                 augmentFont(f1, "msb");
615                 if (!fontloader.available(f1)) {
616                         lyxerr << "faking msb\n";
617                         fontinfo * info = searchFont("msb");
618                         info->family_ = LyXFont::TYPEWRITER_FAMILY;
619                         info->series_ = LyXFont::BOLD_SERIES;
620                 }
621
622                 LyXFont f2;
623                 augmentFont(f2, "msex");
624                 if (!fontloader.available(f2)) {
625                         lyxerr << "faking msex\n";
626                         fontinfo * info = searchFont("msex");
627                         info->family_ = LyXFont::SANS_FAMILY;
628                         info->series_ = LyXFont::BOLD_SERIES;
629                         info->shape_  = LyXFont::ITALIC_SHAPE;
630                 }
631
632                 //{"fakebb", LyXFont::TYPEWRITER_FAMILY, LyXFont::BOLD_SERIES,
633                 //      LyXFont::UP_SHAPE, LColor::math},
634                 //{"fakecal", LyXFont::SANS_FAMILY, LyXFont::MEDIUM_SERIES,
635                 //      LyXFont::ITALIC_SHAPE, LColor::math},
636                 //{"fakefrak", LyXFont::SANS_FAMILY, LyXFont::BOLD_SERIES,
637                 //      LyXFont::ITALIC_SHAPE, LColor::math}
638
639         }
640
641
642         fontinfo * info = searchFont(name);
643         if (info->family_ != def_family)
644                 font.setFamily(info->family_);
645
646         if (info->series_ != def_series)
647                 font.setSeries(info->series_);
648
649         if (info->shape_ != def_shape)
650                 font.setShape(info->shape_);
651
652         if (info->color_ != LColor::none)
653                 font.setColor(info->color_);
654 }
655
656
657 bool math_font_available(string const & /*name*/)
658 {
659         return true;
660 }