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