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