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