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