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