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