]> git.lyx.org Git - lyx.git/blob - src/mathed/math_support.C
replace (ascent, descent, width) triples by a structure 'dimension'
[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         {"not",            slash,      0 },
306         {"mathring",       ring,       0 },
307
308         // Dots
309         {"ldots",          hline3,     0 },
310         {"cdots",          hline3,     0 },
311         {"vdots",          hline3,     1 },
312         {"ddots",          dline3,     0 },
313         {"dotsb",          hline3,     0 },
314         {"dotsc",          hline3,     0 },
315         {"dotsi",          hline3,     0 },
316         {"dotsm",          hline3,     0 },
317         {"dotso",          hline3,     0 }
318 };
319
320
321 map<string, deco_struct> deco_list;
322
323 // sort the table on startup
324 struct init_deco_table {
325         init_deco_table() {
326                 unsigned const n = sizeof(deco_table) / sizeof(deco_table[0]);
327                 for (named_deco_struct * p = deco_table; p != deco_table + n; ++p) {
328                         deco_struct d;
329                         d.data  = p->data;
330                         d.angle = p->angle;
331                         deco_list[p->name]= d;
332                 }
333         }
334 };
335
336 static init_deco_table dummy;
337
338
339 deco_struct const * search_deco(string const & name)
340 {
341         map<string, deco_struct>::const_iterator p = deco_list.find(name);
342         return (p == deco_list.end()) ? 0 : &(p->second);
343 }
344
345
346 } // namespace anon
347
348
349 void mathed_char_dim(LyXFont const & font, unsigned char c, Dimension & dim)
350 {
351         dim.d = font_metrics::descent(c, font);
352         dim.a = font_metrics::ascent(c, font);
353         dim.w = mathed_char_width(font, c);
354 }
355
356
357 int mathed_char_ascent(LyXFont const & font, unsigned char c)
358 {
359         return font_metrics::ascent(c, font);
360 }
361
362
363 int mathed_char_descent(LyXFont const & font, unsigned char c)
364 {
365         return font_metrics::descent(c, font);
366 }
367
368
369 int mathed_char_width(LyXFont const & font, unsigned char c)
370 {
371         return font_metrics::width(c, font);
372 }
373
374
375 void mathed_string_dim(LyXFont const & font,
376         string const & s, int & asc, int & des, int & wid)
377 {
378 }
379
380
381 void mathed_string_dim(LyXFont const & font, string const & s, Dimension & dim)
382 {
383         dim.a = 0;
384         dim.d = 0;
385         for (string::const_iterator it = s.begin(); it != s.end(); ++it) {
386                 dim.a = max(dim.a, font_metrics::ascent(*it, font));
387                 dim.d = max(dim.d, font_metrics::descent(*it, font));
388         }
389         dim.w = font_metrics::width(s, font);
390 }
391
392
393 int mathed_string_width(LyXFont const & font, string const & s)
394 {
395         return font_metrics::width(s, font);
396 }
397
398
399 int mathed_string_ascent(LyXFont const & font, string const & s)
400 {
401         int asc = 0;
402         for (string::const_iterator it = s.begin(); it != s.end(); ++it)
403                 asc = max(asc, font_metrics::ascent(*it, font));
404         return asc;
405 }
406
407
408 int mathed_string_descent(LyXFont const & font, string const & s)
409 {
410         int des = 0;
411         for (string::const_iterator it = s.begin(); it != s.end(); ++it)
412                 des = max(des, font_metrics::descent(*it, font));
413         return des;
414 }
415
416
417
418 void mathed_draw_deco(MathPainterInfo & pi, int x, int y, int w, int h,
419         const string & name)
420 {
421         if (name == ".") {
422                 pi.pain.line(x + w/2, y, x + w/2, y + h,
423                           LColor::mathcursor, Painter::line_onoffdash);
424                 return;
425         }
426
427         deco_struct const * mds = search_deco(name);
428         if (!mds) {
429                 lyxerr << "Deco was not found. Programming error?\n";
430                 lyxerr << "name: '" << name << "'\n";
431                 return;
432         }
433
434         int const n = (w < h) ? w : h;
435         int const r = mds->angle;
436         double const * d = mds->data;
437
438         if (h > 70 && (name == "(" || name == ")"))
439                 d = parenthHigh;
440
441         Matrix mt(r, w, h);
442         Matrix sqmt(r, n, n);
443
444         if (r > 0 && r < 3)
445                 y += h;
446
447         if (r >= 2)
448                 x += w;
449
450         for (int i = 0; d[i]; ) {
451                 int code = int(d[i++]);
452                 if (code & 1) {  // code == 1 || code == 3
453                         double xx = d[i++];
454                         double yy = d[i++];
455                         double x2 = d[i++];
456                         double y2 = d[i++];
457                         if (code == 3)
458                                 sqmt.transform(xx, yy);
459                         else
460                                 mt.transform(xx, yy);
461                         mt.transform(x2, y2);
462                         pi.pain.line(
463                                 x + int(xx + 0.5), y + int(yy + 0.5),
464                                 x + int(x2 + 0.5), y + int(y2 + 0.5),
465                                 LColor::math);
466                 }       else {
467                         int xp[32];
468                         int yp[32];
469                         int const n = int(d[i++]);
470                         for (int j = 0; j < n; ++j) {
471                                 double xx = d[i++];
472                                 double yy = d[i++];
473 //           lyxerr << " " << xx << " " << yy << " ";
474                                 if (code == 4)
475                                         sqmt.transform(xx, yy);
476                                 else
477                                         mt.transform(xx, yy);
478                                 xp[j] = x + int(xx + 0.5);
479                                 yp[j] = y + int(yy + 0.5);
480                                 //  lyxerr << "P[" << j " " << xx << " " << yy << " " << x << " " << y << "]";
481                         }
482                         pi.pain.lines(xp, yp, n, LColor::math);
483                 }
484         }
485 }
486
487
488 void mathed_draw_framebox(MathPainterInfo & pi, int x, int y, MathInset const * p)
489 {
490         if (mathcursor && mathcursor->isInside(p))
491                 pi.pain.rectangle(x, y - p->ascent(), p->width(), p->height(),
492                         LColor::mathframe);
493 }
494
495
496 // In the future maybe we use a better fonts renderer
497 void drawStr(MathPainterInfo & pi, LyXFont const & font,
498         int x, int y, string const & str)
499 {
500         pi.pain.text(x, y, str, font);
501 }
502
503
504 void drawStrRed(MathPainterInfo & pi, int x, int y, string const & str)
505 {
506         LyXFont f = pi.base.font;
507         f.setColor(LColor::latex);
508         pi.pain.text(x, y, str, f);
509 }
510
511
512 void drawStrBlack(MathPainterInfo & pi, int x, int y, string const & str)
513 {
514         LyXFont f = pi.base.font;
515         f.setColor(LColor::black);
516         pi.pain.text(x, y, str, f);
517 }
518
519
520 void drawChar(MathPainterInfo & pi, LyXFont const & font, int x, int y, char c)
521 {
522         pi.pain.text(x, y, c, font);
523 }
524
525
526 void math_font_max_dim(LyXFont const & font, int & asc, int & des)
527 {
528         asc = font_metrics::maxAscent(font);
529         des = font_metrics::maxDescent(font);
530 }
531
532
533 struct fontinfo {
534         string cmd_;
535         LyXFont::FONT_FAMILY family_;
536         LyXFont::FONT_SERIES series_;
537         LyXFont::FONT_SHAPE  shape_;
538         LColor::color        color_;
539 };
540
541
542 LyXFont::FONT_FAMILY const inh_family = LyXFont::INHERIT_FAMILY;
543 LyXFont::FONT_SERIES const inh_series = LyXFont::INHERIT_SERIES;
544 LyXFont::FONT_SHAPE  const inh_shape  = LyXFont::INHERIT_SHAPE; 
545
546
547 // mathnormal should be the first, otherwise the fallback fuerther down
548 // does not work
549 fontinfo fontinfos[] = {
550         {"mathnormal", inh_family,inh_series, LyXFont::UP_SHAPE, LColor::math},
551         {"mathbf", inh_family, LyXFont::BOLD_SERIES, inh_shape, LColor::math},
552         {"mathcal",LyXFont::CMSY_FAMILY, inh_series, inh_shape, LColor::math},
553         {"mathfrak", LyXFont::EUFRAK_FAMILY, inh_series, inh_shape, LColor::math},
554         {"mathrm", LyXFont::ROMAN_FAMILY, inh_series, inh_shape, LColor::math},
555         {"mathsf", LyXFont::SANS_FAMILY, inh_series, inh_shape, LColor::math},
556         {"cmex",   LyXFont::CMEX_FAMILY, inh_series, inh_shape, LColor::math},
557         {"cmm",    LyXFont::CMM_FAMILY, inh_series, inh_shape, LColor::math},
558         {"cmr",    LyXFont::CMR_FAMILY, inh_series, inh_shape, LColor::math},
559         {"cmsy",   LyXFont::CMSY_FAMILY, inh_series, inh_shape, LColor::math},
560         {"eufrak", LyXFont::EUFRAK_FAMILY, inh_series, inh_shape, LColor::math},
561         {"msa",    LyXFont::MSA_FAMILY, inh_series, inh_shape, LColor::math},
562         {"msb",    LyXFont::MSB_FAMILY, inh_series, inh_shape, LColor::math},
563         {"wasy",   LyXFont::WASY_FAMILY, inh_series, inh_shape, LColor::math},
564         {"text",   inh_family, inh_series, inh_shape, LColor::black},
565         {"textbf", inh_family, LyXFont::BOLD_SERIES, inh_shape, LColor::black},
566         {"textit", inh_family, inh_series, LyXFont::ITALIC_SHAPE, LColor::black},
567         {"textmd", inh_family, LyXFont::MEDIUM_SERIES, inh_shape, LColor::black},
568         {"textnormal", inh_family, inh_series, LyXFont::UP_SHAPE, LColor::black},
569         {"textrm", LyXFont::ROMAN_FAMILY, inh_series,LyXFont::UP_SHAPE,LColor::black},
570         {"textsc", inh_family, inh_series, LyXFont::SMALLCAPS_SHAPE, LColor::black},
571         {"textsf", LyXFont::SANS_FAMILY, inh_series, inh_shape, LColor::black},
572         {"textsl", inh_family, inh_series, LyXFont::SLANTED_SHAPE, LColor::black},
573         {"texttt", LyXFont::TYPEWRITER_FAMILY, inh_series, inh_shape, LColor::black},
574         {"textup", inh_family, inh_series, LyXFont::UP_SHAPE, LColor::black},
575
576         // TIPA support
577         {"textipa",   inh_family, inh_series, inh_shape, LColor::black},
578
579         {"lyxtex", inh_family, inh_series, inh_shape, LColor::latex},
580         {"lyxsymbol", LyXFont::SYMBOL_FAMILY, inh_series, inh_shape, LColor::math},
581         {"lyxboldsymbol",
582                 LyXFont::SYMBOL_FAMILY, LyXFont::BOLD_SERIES, inh_shape, LColor::math},
583         {"lyxitsymbol", LyXFont::SYMBOL_FAMILY,
584                 inh_series, LyXFont::ITALIC_SHAPE, LColor::math},
585         {"lyxblacktext", LyXFont::ROMAN_FAMILY,
586                 LyXFont::MEDIUM_SERIES, LyXFont::UP_SHAPE, LColor::black},
587         {"lyxnochange", inh_family, inh_series, inh_shape, LColor::black},
588
589         {"lyxfakebb", LyXFont::TYPEWRITER_FAMILY, LyXFont::BOLD_SERIES,
590                 LyXFont::UP_SHAPE, LColor::math},
591         {"lyxfakecal", LyXFont::SANS_FAMILY, LyXFont::MEDIUM_SERIES,
592                 LyXFont::ITALIC_SHAPE, LColor::math},
593         {"lyxfakefrak", LyXFont::ROMAN_FAMILY, LyXFont::BOLD_SERIES,
594                 LyXFont::ITALIC_SHAPE, LColor::math}
595 };
596
597
598 fontinfo * lookupFont(string const & name)
599 {
600         //lyxerr << "searching font '" << name << "'\n"; 
601         int const n = sizeof(fontinfos) / sizeof(fontinfo);
602         for (int i = 0; i < n; ++i)
603                 if (fontinfos[i].cmd_ == name) {
604                         //lyxerr << "found '" << i << "'\n"; 
605                         return fontinfos + i;
606                 }
607         return 0;
608 }
609
610
611 fontinfo * searchFont(string const & name)
612 {
613         fontinfo * f = lookupFont(name);
614         return f ? f : fontinfos;
615         // this should be mathnormal
616         //return searchFont("mathnormal");
617 }
618
619
620 bool isFontName(string const & name)
621 {
622         return lookupFont(name);
623 }
624
625
626 LyXFont getFont(string const & name)
627 {
628         LyXFont font;
629         augmentFont(font, name);
630         return font;
631 }
632
633
634 void fakeFont(string const & orig, string const & fake)
635 {
636         fontinfo * forig = searchFont(orig);
637         fontinfo * ffake = searchFont(fake);
638         if (forig && ffake) {
639                 forig->family_ = ffake->family_;
640                 forig->series_ = ffake->series_;
641                 forig->shape_  = ffake->shape_;
642                 forig->color_  = ffake->color_;
643         } else {
644                 lyxerr << "Can't fake font '" << orig << "' with '" << fake << "'\n";
645         }
646 }
647
648
649 void augmentFont(LyXFont & font, string const & name)
650 {
651         static bool initialized = false;
652         if (!initialized) {
653                 initialized = true;
654
655                 // fake fonts if necessary
656                 if (!fontloader.available(getFont("mathfrak")))
657                         fakeFont("mathfrak", "lyxfakefrak");
658                 if (!fontloader.available(getFont("mathcal")))
659                         fakeFont("mathcal", "lyxfakecal");
660         }
661         fontinfo * info = searchFont(name);
662         if (info->family_ != inh_family)
663                 font.setFamily(info->family_);
664         if (info->series_ != inh_series)
665                 font.setSeries(info->series_);
666         if (info->shape_ != inh_shape)
667                 font.setShape(info->shape_);
668         if (info->color_ != LColor::none)
669                 font.setColor(info->color_);
670 }