]> git.lyx.org Git - lyx.git/blob - src/mathed/math_support.C
preview as preview can...
[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_defs.h"
9 #include "math_inset.h"
10 #include "math_parser.h"
11 #include "frontends/Painter.h"
12 #include "frontends/font_metrics.h"
13 #include "frontends/font_loader.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.00, 0.8,  0.25, 0.2,  0.75, 0.8,  1.00, 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 & pi, int x, int y, int w, int h,
414         const string & name)
415 {
416         if (name == ".") {
417                 pi.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                         pi.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                         pi.pain.lines(xp, yp, n, LColor::math);
478                 }
479         }
480 }
481
482
483 void mathed_draw_framebox(MathPainterInfo & pi, int x, int y, MathInset const * p)
484 {
485         if (mathcursor && mathcursor->isInside(p))
486                 pi.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 & pi, LyXFont const & font,
493         int x, int y, string const & str)
494 {
495         pi.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 struct fontinfo {
529         string cmd_;
530         LyXFont::FONT_FAMILY family_;
531         LyXFont::FONT_SERIES series_;
532         LyXFont::FONT_SHAPE  shape_;
533         LColor::color        color_;
534 };
535
536
537 LyXFont::FONT_FAMILY const inh_family = LyXFont::INHERIT_FAMILY;
538 LyXFont::FONT_SERIES const inh_series = LyXFont::INHERIT_SERIES;
539 LyXFont::FONT_SHAPE  const inh_shape  = LyXFont::INHERIT_SHAPE; 
540
541
542
543 fontinfo fontinfos[] = {
544         {"cmex",   LyXFont::CMEX_FAMILY, inh_series, inh_shape, LColor::math},
545         {"cmm",    LyXFont::CMM_FAMILY, inh_series, inh_shape, LColor::math},
546         {"cmr",    LyXFont::CMR_FAMILY, inh_series, inh_shape, LColor::math},
547         {"cmsy",   LyXFont::CMSY_FAMILY, inh_series, inh_shape, LColor::math},
548         {"eufrak", LyXFont::EUFRAK_FAMILY, inh_series, inh_shape, LColor::math},
549         {"mathbf", inh_family, LyXFont::BOLD_SERIES, inh_shape, LColor::math},
550         {"mathcal",LyXFont::CMSY_FAMILY, inh_series, inh_shape, LColor::math},
551         {"mathfrak", LyXFont::EUFRAK_FAMILY, inh_series, inh_shape, LColor::math},
552         {"mathnormal", inh_family,inh_series, LyXFont::UP_SHAPE, LColor::math},
553         {"mathrm", LyXFont::ROMAN_FAMILY, inh_series, inh_shape, LColor::math},
554         {"mathsf", LyXFont::SANS_FAMILY, inh_series, inh_shape, LColor::math},
555         {"msa",    LyXFont::MSA_FAMILY, inh_series, inh_shape, LColor::math},
556         {"msb",    LyXFont::MSB_FAMILY, inh_series, inh_shape, LColor::math},
557         {"textbf", inh_family, LyXFont::BOLD_SERIES, inh_shape, LColor::black},
558         {"textit", inh_family, inh_series, LyXFont::ITALIC_SHAPE, LColor::black},
559         {"textmd", inh_family, LyXFont::MEDIUM_SERIES, inh_shape, LColor::black},
560         {"textnormal", inh_family, inh_series, LyXFont::UP_SHAPE, LColor::black},
561         {"textrm", LyXFont::ROMAN_FAMILY, inh_series,LyXFont::UP_SHAPE,LColor::black},
562         {"textsc", inh_family, inh_series, LyXFont::SMALLCAPS_SHAPE, LColor::black},
563         {"textsf", LyXFont::SANS_FAMILY, inh_series, inh_shape, LColor::black},
564         {"textsl", inh_family, inh_series, LyXFont::SLANTED_SHAPE, LColor::black},
565         {"texttt", LyXFont::TYPEWRITER_FAMILY, inh_series, inh_shape, LColor::black},
566         {"textup", inh_family, inh_series, LyXFont::UP_SHAPE, LColor::black},
567
568         {"lyxtex", inh_family, inh_series, inh_shape, LColor::latex},
569         {"lyxsymbol", LyXFont::SYMBOL_FAMILY, inh_series, inh_shape, LColor::math},
570         {"lyxboldsymbol",
571                 LyXFont::SYMBOL_FAMILY, LyXFont::BOLD_SERIES, inh_shape, LColor::math},
572         {"lyxitsymbol", LyXFont::SYMBOL_FAMILY,
573                 inh_series, LyXFont::ITALIC_SHAPE, LColor::math},
574         {"lyxblacktext", LyXFont::ROMAN_FAMILY,
575                 LyXFont::MEDIUM_SERIES, LyXFont::UP_SHAPE, LColor::black},
576         {"lyxnochange", inh_family, inh_series, inh_shape, LColor::black},
577
578         {"lyxfakebb", LyXFont::TYPEWRITER_FAMILY, LyXFont::BOLD_SERIES,
579                 LyXFont::UP_SHAPE, LColor::math},
580         {"lyxfakecal", LyXFont::SANS_FAMILY, LyXFont::MEDIUM_SERIES,
581                 LyXFont::ITALIC_SHAPE, LColor::math},
582         {"lyxfakefrak", LyXFont::ROMAN_FAMILY, LyXFont::BOLD_SERIES,
583                 LyXFont::ITALIC_SHAPE, LColor::math}
584 };
585
586
587 fontinfo * searchFont(string const & name)
588 {
589         int const n = sizeof(fontinfos) / sizeof(fontinfo);
590         //lyxerr << "searching font '" << name << "'\n"; 
591         for (int i = 0; i < n; ++i)
592                 if (fontinfos[i].cmd_ == name) {
593                         //lyxerr << "found '" << i << "'\n"; 
594                         return fontinfos + i;
595                 }
596         return searchFont("mathnormal");
597 }
598
599
600 LyXFont getFont(string const & name)
601 {
602         LyXFont font;
603         augmentFont(font, name);
604         return font;
605 }
606
607
608 void fakeFont(string const & orig, string const & fake)
609 {
610         fontinfo * forig = searchFont(orig);
611         fontinfo * ffake = searchFont(fake);
612         if (forig && ffake) {
613                 forig->family_ = ffake->family_;
614                 forig->series_ = ffake->series_;
615                 forig->shape_  = ffake->shape_;
616                 forig->color_  = ffake->color_;
617         } else {
618                 lyxerr << "Can't fake font '" << orig << "' with '" << fake << "'\n";
619         }
620 }
621
622 void augmentFont(LyXFont & font, string const & name)
623 {
624         static bool initialized = false;
625         if (!initialized) {
626                 initialized = true;
627
628                 // fake fonts if necessary
629                 if (!fontloader.available(getFont("mathfrak")))
630                         fakeFont("mathfrak", "lyxfakefrak");
631                 if (!fontloader.available(getFont("mathcal")))
632                         fakeFont("mathcal", "lyxfakecal");
633         }
634         fontinfo * info = searchFont(name);
635         if (info->family_ != inh_family)
636                 font.setFamily(info->family_);
637         if (info->series_ != inh_series)
638                 font.setSeries(info->series_);
639         if (info->shape_ != inh_shape)
640                 font.setShape(info->shape_);
641         if (info->color_ != LColor::none)
642                 font.setColor(info->color_);
643 }