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