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