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