]> git.lyx.org Git - lyx.git/blob - src/mathed/math_support.C
the FuncRequest changes
[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 "math_cursor.h"
8 #include "math_inset.h"
9 #include "math_parser.h"
10 #include "math_metricsinfo.h"
11 #include "frontends/Painter.h"
12 #include "frontends/font_metrics.h"
13 #include "frontends/lyx_gui.h"
14 #include "debug.h"
15 #include "commandtags.h"
16 #include "dimension.h"
17
18 using std::map;
19 using std::endl;
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         {"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, unsigned char c, Dimension & dim)
350 {
351         dim.d = font_metrics::descent(c, font);
352         dim.a = font_metrics::ascent(c, font);
353         dim.w = mathed_char_width(font, c);
354 }
355
356
357 int mathed_char_ascent(LyXFont const & font, unsigned char c)
358 {
359         return font_metrics::ascent(c, font);
360 }
361
362
363 int mathed_char_descent(LyXFont const & font, unsigned char c)
364 {
365         return font_metrics::descent(c, font);
366 }
367
368
369 int mathed_char_width(LyXFont const & font, unsigned char c)
370 {
371         return font_metrics::width(c, font);
372 }
373
374
375 void mathed_string_dim(LyXFont const & font, string const & s, Dimension & dim)
376 {
377 #if 1
378         dim.a = 0;
379         dim.d = 0;
380         for (string::const_iterator it = s.begin(); it != s.end(); ++it) {
381                 dim.a = max(dim.a, font_metrics::ascent(*it, font));
382                 dim.d = max(dim.d, font_metrics::descent(*it, font));
383         }
384 #else
385         dim.a = font_metrics::maxAscent(font);
386         dim.d = font_metrics::maxDescent(font);
387 #endif
388         dim.w = font_metrics::width(s, font);
389 }
390
391
392 int mathed_string_width(LyXFont const & font, string const & s)
393 {
394         return font_metrics::width(s, font);
395 }
396
397
398 void mathed_draw_deco(MathPainterInfo & pi, int x, int y, int w, int h,
399         const string & name)
400 {
401         if (name == ".") {
402                 pi.pain.line(x + w/2, y, x + w/2, y + h,
403                           LColor::mathcursor, Painter::line_onoffdash);
404                 return;
405         }
406
407         deco_struct const * mds = search_deco(name);
408         if (!mds) {
409                 lyxerr << "Deco was not found. Programming error?\n";
410                 lyxerr << "name: '" << name << "'\n";
411                 return;
412         }
413
414         int const n = (w < h) ? w : h;
415         int const r = mds->angle;
416         double const * d = mds->data;
417
418         if (h > 70 && (name == "(" || name == ")"))
419                 d = parenthHigh;
420
421         Matrix mt(r, w, h);
422         Matrix sqmt(r, n, n);
423
424         if (r > 0 && r < 3)
425                 y += h;
426
427         if (r >= 2)
428                 x += w;
429
430         for (int i = 0; d[i]; ) {
431                 int code = int(d[i++]);
432                 if (code & 1) {  // code == 1 || code == 3
433                         double xx = d[i++];
434                         double yy = d[i++];
435                         double x2 = d[i++];
436                         double y2 = d[i++];
437                         if (code == 3)
438                                 sqmt.transform(xx, yy);
439                         else
440                                 mt.transform(xx, yy);
441                         mt.transform(x2, y2);
442                         pi.pain.line(
443                                 int(x + xx + 0.5), int(y + yy + 0.5),
444                                 int(x + x2 + 0.5), int(y + y2 + 0.5),
445                                 LColor::math);
446                 }       else {
447                         int xp[32];
448                         int yp[32];
449                         int const n = int(d[i++]);
450                         for (int j = 0; j < n; ++j) {
451                                 double xx = d[i++];
452                                 double yy = d[i++];
453 //           lyxerr << " " << xx << " " << yy << " ";
454                                 if (code == 4)
455                                         sqmt.transform(xx, yy);
456                                 else
457                                         mt.transform(xx, yy);
458                                 xp[j] = int(x + xx + 0.5);
459                                 yp[j] = int(y + yy + 0.5);
460                                 //  lyxerr << "P[" << j " " << xx << " " << yy << " " << x << " " << y << "]";
461                         }
462                         pi.pain.lines(xp, yp, n, LColor::math);
463                 }
464         }
465 }
466
467
468 void mathed_draw_framebox(MathPainterInfo & pi, int x, int y, MathInset const * p)
469 {
470         if (mathcursor && mathcursor->isInside(p))
471                 pi.pain.rectangle(x, y - p->ascent(), p->width(), p->height(),
472                         LColor::mathframe);
473 }
474
475
476 // In the future maybe we use a better fonts renderer
477 void drawStr(MathPainterInfo & pi, LyXFont const & font,
478         int x, int y, string const & str)
479 {
480         pi.pain.text(x, y, str, font);
481 }
482
483
484 void drawStrRed(MathPainterInfo & pi, int x, int y, string const & str)
485 {
486         LyXFont f = pi.base.font;
487         f.setColor(LColor::latex);
488         pi.pain.text(x, y, str, f);
489 }
490
491
492 void drawStrBlack(MathPainterInfo & pi, int x, int y, string const & str)
493 {
494         LyXFont f = pi.base.font;
495         f.setColor(LColor::black);
496         pi.pain.text(x, y, str, f);
497 }
498
499
500 void drawChar(MathPainterInfo & pi, LyXFont const & font, int x, int y, char c)
501 {
502         pi.pain.text(x, y, c, font);
503 }
504
505
506 void math_font_max_dim(LyXFont const & font, int & asc, int & des)
507 {
508         asc = font_metrics::maxAscent(font);
509         des = font_metrics::maxDescent(font);
510 }
511
512
513 struct fontinfo {
514         string cmd_;
515         LyXFont::FONT_FAMILY family_;
516         LyXFont::FONT_SERIES series_;
517         LyXFont::FONT_SHAPE  shape_;
518         LColor::color        color_;
519 };
520
521
522 LyXFont::FONT_FAMILY const inh_family = LyXFont::INHERIT_FAMILY;
523 LyXFont::FONT_SERIES const inh_series = LyXFont::INHERIT_SERIES;
524 LyXFont::FONT_SHAPE  const inh_shape  = LyXFont::INHERIT_SHAPE; 
525
526
527 // mathnormal should be the first, otherwise the fallback further down
528 // does not work
529 fontinfo fontinfos[] = {
530         {"mathnormal",
531                 inh_family, LyXFont::MEDIUM_SERIES, LyXFont::UP_SHAPE, LColor::math},
532         {"mathbf", inh_family, LyXFont::BOLD_SERIES, inh_shape, LColor::math},
533         {"mathcal",LyXFont::CMSY_FAMILY, inh_series, inh_shape, LColor::math},
534         {"mathfrak", LyXFont::EUFRAK_FAMILY, inh_series, inh_shape, LColor::math},
535         {"mathrm", LyXFont::ROMAN_FAMILY, inh_series, inh_shape, LColor::math},
536         {"mathsf", LyXFont::SANS_FAMILY, inh_series, inh_shape, LColor::math},
537         {"cmex",   LyXFont::CMEX_FAMILY, inh_series, inh_shape, LColor::math},
538         {"cmm",    LyXFont::CMM_FAMILY, inh_series, inh_shape, LColor::math},
539         {"cmr",    LyXFont::CMR_FAMILY, inh_series, inh_shape, LColor::math},
540         {"cmsy",   LyXFont::CMSY_FAMILY, inh_series, inh_shape, LColor::math},
541         {"eufrak", LyXFont::EUFRAK_FAMILY, inh_series, inh_shape, LColor::math},
542         {"msa",    LyXFont::MSA_FAMILY, inh_series, inh_shape, LColor::math},
543         {"msb",    LyXFont::MSB_FAMILY, inh_series, inh_shape, LColor::math},
544         {"wasy",   LyXFont::WASY_FAMILY, inh_series, inh_shape, LColor::math},
545         {"text",   inh_family, inh_series, inh_shape, LColor::black},
546         {"textbf", inh_family, LyXFont::BOLD_SERIES, inh_shape, LColor::black},
547         {"textit", inh_family, inh_series, LyXFont::ITALIC_SHAPE, LColor::black},
548         {"textmd", inh_family, LyXFont::MEDIUM_SERIES, inh_shape, LColor::black},
549         {"textnormal", inh_family, inh_series, LyXFont::UP_SHAPE, LColor::black},
550         {"textrm", LyXFont::ROMAN_FAMILY, inh_series,LyXFont::UP_SHAPE,LColor::black},
551         {"textsc", inh_family, inh_series, LyXFont::SMALLCAPS_SHAPE, LColor::black},
552         {"textsf", LyXFont::SANS_FAMILY, inh_series, inh_shape, LColor::black},
553         {"textsl", inh_family, inh_series, LyXFont::SLANTED_SHAPE, LColor::black},
554         {"texttt", LyXFont::TYPEWRITER_FAMILY, inh_series, inh_shape, LColor::black},
555         {"textup", inh_family, inh_series, LyXFont::UP_SHAPE, LColor::black},
556
557         // TIPA support
558         {"textipa",   inh_family, inh_series, inh_shape, LColor::black},
559
560         {"lyxtex", inh_family, inh_series, inh_shape, LColor::latex},
561         {"lyxert", LyXFont::TYPEWRITER_FAMILY, inh_series, inh_shape, LColor::latex},
562         {"lyxsymbol", LyXFont::SYMBOL_FAMILY, inh_series, inh_shape, LColor::math},
563         {"lyxboldsymbol",
564                 LyXFont::SYMBOL_FAMILY, LyXFont::BOLD_SERIES, inh_shape, LColor::math},
565         {"lyxitsymbol", LyXFont::SYMBOL_FAMILY,
566                 inh_series, LyXFont::ITALIC_SHAPE, LColor::math},
567         {"lyxblacktext", LyXFont::ROMAN_FAMILY,
568                 LyXFont::MEDIUM_SERIES, LyXFont::UP_SHAPE, LColor::black},
569         {"lyxnochange", inh_family, inh_series, inh_shape, LColor::black},
570
571         {"lyxfakebb", LyXFont::TYPEWRITER_FAMILY, LyXFont::BOLD_SERIES,
572                 LyXFont::UP_SHAPE, LColor::math},
573         {"lyxfakecal", LyXFont::SANS_FAMILY, LyXFont::MEDIUM_SERIES,
574                 LyXFont::ITALIC_SHAPE, LColor::math},
575         {"lyxfakefrak", LyXFont::ROMAN_FAMILY, LyXFont::BOLD_SERIES,
576                 LyXFont::ITALIC_SHAPE, LColor::math}
577 };
578
579
580 fontinfo * lookupFont(string const & name)
581 {
582         //lyxerr << "searching font '" << name << "'\n"; 
583         int const n = sizeof(fontinfos) / sizeof(fontinfo);
584         for (int i = 0; i < n; ++i)
585                 if (fontinfos[i].cmd_ == name) {
586                         //lyxerr << "found '" << i << "'\n"; 
587                         return fontinfos + i;
588                 }
589         return 0;
590 }
591
592
593 fontinfo * searchFont(string const & name)
594 {
595         fontinfo * f = lookupFont(name);
596         return f ? f : fontinfos;
597         // this should be mathnormal
598         //return searchFont("mathnormal");
599 }
600
601
602 bool isFontName(string const & name)
603 {
604         return lookupFont(name);
605 }
606
607
608 LyXFont getFont(string const & name)
609 {
610         LyXFont font;
611         augmentFont(font, name);
612         return font;
613 }
614
615
616 void fakeFont(string const & orig, string const & fake)
617 {
618         fontinfo * forig = searchFont(orig);
619         fontinfo * ffake = searchFont(fake);
620         if (forig && ffake) {
621                 forig->family_ = ffake->family_;
622                 forig->series_ = ffake->series_;
623                 forig->shape_  = ffake->shape_;
624                 forig->color_  = ffake->color_;
625         } else {
626                 lyxerr << "Can't fake font '" << orig << "' with '" << fake << "'\n";
627         }
628 }
629
630
631 void augmentFont(LyXFont & font, string const & name)
632 {
633         static bool initialized = false;
634         if (!initialized) {
635                 initialized = true;
636                 // fake fonts if necessary
637                 if (!lyx_gui::font_available(getFont("mathfrak")))
638                         fakeFont("mathfrak", "lyxfakefrak");
639                 if (!lyx_gui::font_available(getFont("mathcal")))
640                         fakeFont("mathcal", "lyxfakecal");
641         }
642         fontinfo * info = searchFont(name);
643         if (info->family_ != inh_family)
644                 font.setFamily(info->family_);
645         if (info->series_ != inh_series)
646                 font.setSeries(info->series_);
647         if (info->shape_ != inh_shape)
648                 font.setShape(info->shape_);
649         if (info->color_ != LColor::none)
650                 font.setColor(info->color_);
651 }