1 /**
2 * \file MathSupport.cpp
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
16 #include "InsetMathFont.h"
17 #include "InsetMathSymbol.h"
18 #include "Length.h"
19 #include "MathData.h"
20 #include "MathFactory.h"
21 #include "MathParser.h"
22 #include "MathStream.h"
23
24 #include "LaTeXFeatures.h"
25 #include "MetricsInfo.h"
26
27 #include "frontends/FontLoader.h"
28 #include "frontends/FontMetrics.h"
29 #include "frontends/Painter.h"
30
31 #include "support/debug.h"
32 #include "support/docstream.h"
33 #include "support/lassert.h"
34 #include "support/lyxlib.h"
35
36 #include <map>
37 #include <algorithm>
38
39 using namespace std;
40
41 namespace lyx {
42
43 using frontend::Painter;
44
45
46 ///
47 class Matrix {
48 public:
49 ///
50 Matrix(int, double, double);
51 ///
52 void transform(double &, double &);
53 private:
54 ///
55 double m_[2][2];
56 };
57
58
Matrix(int code,double x,double y)59 Matrix::Matrix(int code, double x, double y)
60 {
61 double const cs = (code & 1) ? 0 : (1 - code);
62 double const sn = (code & 1) ? (2 - code) : 0;
63 m_[0][0] = cs * x;
64 m_[0][1] = sn * x;
65 m_[1][0] = -sn * y;
66 m_[1][1] = cs * y;
67 }
68
69
transform(double & x,double & y)70 void Matrix::transform(double & x, double & y)
71 {
72 double xx = m_[0][0] * x + m_[0][1] * y;
73 double yy = m_[1][0] * x + m_[1][1] * y;
74 x = xx;
75 y = yy;
76 }
77
78
79
80 namespace {
81
82 /*
83 * Internal struct of a drawing: code n x1 y1 ... xn yn, where code is:
84 * 0 = end, 1 = line, 2 = polyline, 3 = square line, 4 = square polyline
85 * 5 = rounded thick line (i.e. dot for short line)
86 */
87
88
89 double const parenthHigh[] = {
90 2, 13,
91 0.9840, 0.0014, 0.7143, 0.0323, 0.4603, 0.0772,
92 0.2540, 0.1278, 0.1746, 0.1966, 0.0952, 0.3300,
93 0.0950, 0.5000, 0.0952, 0.6700, 0.1746, 0.8034,
94 0.2540, 0.8722, 0.4603, 0.9228, 0.7143, 0.9677,
95 0.9840, 0.9986,
96 0
97 };
98
99
100 double const parenth[] = {
101 2, 13,
102 0.9930, 0.0071, 0.7324, 0.0578, 0.5141, 0.1126,
103 0.3380, 0.1714, 0.2183, 0.2333, 0.0634, 0.3621,
104 0.0141, 0.5000, 0.0563, 0.6369, 0.2113, 0.7647,
105 0.3310, 0.8276, 0.5070, 0.8864, 0.7254, 0.9412,
106 0.9930, 0.9919,
107 0
108 };
109
110
111 double const brace[] = {
112 2, 21,
113 0.9492, 0.0020, 0.9379, 0.0020, 0.7458, 0.0243,
114 0.5819, 0.0527, 0.4859, 0.0892, 0.4463, 0.1278,
115 0.4463, 0.3732, 0.4011, 0.4199, 0.2712, 0.4615,
116 0.0734, 0.4919, 0.0113, 0.5000, 0.0734, 0.5081,
117 0.2712, 0.5385, 0.4011, 0.5801, 0.4463, 0.6268,
118 0.4463, 0.8722, 0.4859, 0.9108, 0.5819, 0.9473,
119 0.7458, 0.9757, 0.9379, 0.9980, 0.9492, 0.9980,
120 0
121 };
122
123
124 double const mapsto[] = {
125 2, 3,
126 0.75, 0.015, 0.95, 0.5, 0.75, 0.985,
127 1, 0.015, 0.475, 0.945, 0.475,
128 1, 0.015, 0.015, 0.015, 0.985,
129 0
130 };
131
132
133 double const lhook[] = {
134 2, 3,
135 0.25, 0.015, 0.05, 0.5, 0.25, 0.985,
136 1, 0.015, 0.475, 0.7, 0.475,
137 2, 5,
138 0.7, 0.015, 0.825, 0.15, 0.985, 0.25,
139 0.825, 0.35, 0.7, 0.475,
140 0
141 };
142
143
144 double const rhook[] = {
145 2, 3,
146 0.75, 0.015, 0.95, 0.5, 0.75, 0.985,
147 1, 0.3, 0.475, 0.985, 0.475,
148 2, 5,
149 0.3, 0.015, 0.175, 0.15, 0.05, 0.25,
150 0.175, 0.35, 0.3, 0.475,
151 0
152 };
153
154
155 double const LRArrow[] = {
156 2, 3,
157 0.25, 0.015, 0.05, 0.5, 0.25, 0.985,
158 2, 3,
159 0.75, 0.015, 0.95, 0.5, 0.75, 0.985,
160 1, 0.2, 0.8, 0.8, 0.8,
161 1, 0.2, 0.2, 0.8, 0.2,
162 0
163 };
164
165
166 double const LArrow[] = {
167 2, 3,
168 0.25, 0.015, 0.05, 0.5, 0.25, 0.985,
169 1, 0.2, 0.8, 0.985, 0.8,
170 1, 0.2, 0.2, 0.985, 0.2,
171 0
172 };
173
174
175 double const lharpoondown[] = {
176 2, 2,
177 0.015, 0.5, 0.25, 0.985,
178 1, 0.02, 0.475, 0.985, 0.475,
179 0
180 };
181
182
183 double const lharpoonup[] = {
184 2, 2,
185 0.25, 0.015, 0.015, 0.5,
186 1, 0.02, 0.525, 0.985, 0.525,
187 0
188 };
189
190
191 double const lrharpoons[] = {
192 2, 2,
193 0.25, 0.015, 0.015, 0.225,
194 1, 0.02, 0.23, 0.985, 0.23,
195 2, 2,
196 0.75, 0.985, 0.985, 0.775,
197 1, 0.02, 0.7, 0.980, 0.7,
198 0
199 };
200
201
202 double const rlharpoons[] = {
203 2, 2,
204 0.75, 0.015, 0.985, 0.225,
205 1, 0.02, 0.23, 0.985, 0.23,
206 2, 2,
207 0.25, 0.985, 0.015, 0.775,
208 1, 0.02, 0.7, 0.980, 0.7,
209 0
210 };
211
212
213 double const arrow[] = {
214 4, 7,
215 0.0150, 0.7500, 0.2000, 0.6000, 0.3500, 0.3500,
216 0.5000, 0.0500, 0.6500, 0.3500, 0.8000, 0.6000,
217 0.9500, 0.7500,
218 3, 0.5000, 0.1500, 0.5000, 0.9500,
219 0
220 };
221
222
223 double const Arrow[] = {
224 4, 7,
225 0.0150, 0.7500, 0.2000, 0.6000, 0.3500, 0.3500,
226 0.5000, 0.0500, 0.6500, 0.3500, 0.8000, 0.6000,
227 0.9500, 0.7500,
228 3, 0.3500, 0.5000, 0.3500, 0.9500,
229 3, 0.6500, 0.5000, 0.6500, 0.9500,
230 0
231 };
232
233
234 double const udarrow[] = {
235 2, 3,
236 0.015, 0.25, 0.5, 0.05, 0.95, 0.25,
237 2, 3,
238 0.015, 0.75, 0.5, 0.95, 0.95, 0.75,
239 1, 0.5, 0.1, 0.5, 0.9,
240 0
241 };
242
243
244 double const Udarrow[] = {
245 2, 3,
246 0.015, 0.25, 0.5, 0.05, 0.95, 0.25,
247 2, 3,
248 0.015, 0.75, 0.5, 0.95, 0.95, 0.75,
249 1, 0.35, 0.2, 0.35, 0.8,
250 1, 0.65, 0.2, 0.65, 0.8,
251 0
252 };
253
254
255 double const brack[] = {
256 2, 4,
257 0.95, 0.05, 0.05, 0.05, 0.05, 0.95, 0.95, 0.95,
258 0
259 };
260
261
262 double const dbrack[] = {
263 2, 4,
264 0.95, 0.05, 0.05, 0.05, 0.05, 0.95, 0.95, 0.95,
265 2, 2,
266 0.50, 0.05, 0.50, 0.95,
267 0
268 };
269
270
271 double const corner[] = {
272 2, 3,
273 0.95, 0.05, 0.05, 0.05, 0.05, 0.95,
274 0
275 };
276
277
278 double const angle[] = {
279 2, 3,
280 1, 0, 0.05, 0.5, 1, 1,
281 0
282 };
283
284
285 double const slash[] = {
286 1, 0.95, 0.05, 0.05, 0.95,
287 0
288 };
289
290
291 double const hline[] = {
292 1, 0.00, 0.5, 1.0, 0.5,
293 0
294 };
295
296
297 double const dot[] = {
298 // 1, 0.5, 0.2, 0.5, 0.2,
299 // 1, 0.4, 0.4, 0.6, 0.4,
300 // 1, 0.5, 0.5, 0.5, 0.5,
301 5, 0.4, 0.4, 0.6, 0.4,
302 0
303 };
304
305
306 double const ddot[] = {
307 5, 0.0, 0.4, 0.3, 0.4,
308 5, 0.6, 0.4, 1.0, 0.4,
309 0
310 };
311
312
313 double const dddot[] = {
314 1, 0.1, 0.5, 0.2, 0.5,
315 1, 0.45, 0.5, 0.55, 0.5,
316 1, 0.8, 0.5, 0.9, 0.5,
317 0
318 };
319
320
321 double const ddddot[] = {
322 1, 0.1, 0.5, 0.2, 0.5,
323 1, 0.45, 0.5, 0.55, 0.5,
324 1, 0.8, 0.5, 0.9, 0.5,
325 1, 1.15, 0.5, 1.25, 0.5,
326 0
327 };
328
329
330 double const hline3[] = {
331 1, 0.1, 0, 0.15, 0,
332 1, 0.475, 0, 0.525, 0,
333 1, 0.85, 0, 0.9, 0,
334 0
335 };
336
337
338 double const dline3[] = {
339 1, 0.1, 0.1, 0.15, 0.15,
340 1, 0.475, 0.475, 0.525, 0.525,
341 1, 0.85, 0.85, 0.9, 0.9,
342 0
343 };
344
345
346 double const ring[] = {
347 2, 5,
348 0.5, 0.8, 0.8, 0.5, 0.5, 0.2, 0.2, 0.5, 0.5, 0.8,
349 0
350 };
351
352
353 double const vert[] = {
354 1, 0.5, 0.05, 0.5, 0.95,
355 0
356 };
357
358
359 double const Vert[] = {
360 1, 0.3, 0.05, 0.3, 0.95,
361 1, 0.7, 0.05, 0.7, 0.95,
362 0
363 };
364
365
366 double const tilde[] = {
367 2, 4,
368 0.00, 0.8, 0.25, 0.2, 0.75, 0.8, 1.00, 0.2,
369 0
370 };
371
372
373 struct deco_struct {
374 double const * data;
375 int angle;
376 };
377
378 struct named_deco_struct {
379 char const * name;
380 double const * data;
381 int angle;
382 };
383
384 named_deco_struct deco_table[] = {
385 // Decorations
386 {"widehat", angle, 3 },
387 {"widetilde", tilde, 0 },
388 {"underbar", hline, 0 },
389 {"underline", hline, 0 },
390 {"overline", hline, 0 },
391 {"underbrace", brace, 1 },
392 {"overbrace", brace, 3 },
393 {"overleftarrow", arrow, 1 },
394 {"overrightarrow", arrow, 3 },
395 {"overleftrightarrow", udarrow, 1 },
396 {"xhookleftarrow", lhook, 0 },
397 {"xhookrightarrow", rhook, 0 },
398 {"xleftarrow", arrow, 1 },
399 {"xLeftarrow", LArrow, 0 },
400 {"xleftharpoondown", lharpoondown, 0 },
401 {"xleftharpoonup", lharpoonup, 0 },
402 {"xleftrightharpoons", lrharpoons, 0 },
403 {"xleftrightarrow", udarrow, 1 },
404 {"xLeftrightarrow", LRArrow, 0 },
405 {"xmapsto", mapsto, 0 },
406 {"xrightarrow", arrow, 3 },
407 {"xRightarrow", LArrow, 2 },
408 {"xrightharpoondown", lharpoonup, 2 },
409 {"xrightharpoonup", lharpoondown, 2 },
410 {"xrightleftharpoons", rlharpoons, 0 },
411 {"underleftarrow", arrow, 1 },
412 {"underrightarrow", arrow, 3 },
413 {"underleftrightarrow", udarrow, 1 },
414 {"undertilde", tilde, 0 },
415 {"utilde", tilde, 0 },
416
417 // Delimiters
418 {"(", parenth, 0 },
419 {")", parenth, 2 },
420 {"{", brace, 0 },
421 {"}", brace, 2 },
422 {"lbrace", brace, 0 },
423 {"rbrace", brace, 2 },
424 {"[", brack, 0 },
425 {"]", brack, 2 },
426 {"llbracket", dbrack, 0 },
427 {"rrbracket", dbrack, 2 },
428 {"|", vert, 0 },
429 {"/", slash, 0 },
430 {"slash", slash, 0 },
431 {"vert", vert, 0 },
432 {"lvert", vert, 0 },
433 {"rvert", vert, 0 },
434 {"Vert", Vert, 0 },
435 {"lVert", Vert, 0 },
436 {"rVert", Vert, 0 },
437 {"'", slash, 1 },
438 {"<", angle, 0 },
439 {">", angle, 2 },
440 {"\\", slash, 1 },
441 {"backslash", slash, 1 },
442 {"langle", angle, 0 },
443 {"lceil", corner, 0 },
444 {"lfloor", corner, 1 },
445 {"rangle", angle, 2 },
446 {"rceil", corner, 3 },
447 {"rfloor", corner, 2 },
448 {"downarrow", arrow, 2 },
449 {"Downarrow", Arrow, 2 },
450 {"uparrow", arrow, 0 },
451 {"Uparrow", Arrow, 0 },
452 {"updownarrow", udarrow, 0 },
453 {"Updownarrow", Udarrow, 0 },
454
455 // Accents
456 {"ddot", ddot, 0 },
457 {"dddot", dddot, 0 },
458 {"ddddot", ddddot, 0 },
459 {"hat", angle, 3 },
460 {"grave", slash, 1 },
461 {"acute", slash, 0 },
462 {"tilde", tilde, 0 },
463 {"bar", hline, 0 },
464 {"dot", dot, 0 },
465 {"check", angle, 1 },
466 {"breve", parenth, 1 },
467 {"vec", arrow, 3 },
468 {"mathring", ring, 0 },
469
470 // Dots
471 {"dots", hline3, 0 },
472 {"ldots", hline3, 0 },
473 {"cdots", hline3, 0 },
474 {"vdots", hline3, 1 },
475 {"ddots", dline3, 0 },
476 {"adots", dline3, 1 },
477 {"iddots", dline3, 1 },
478 {"dotsb", hline3, 0 },
479 {"dotsc", hline3, 0 },
480 {"dotsi", hline3, 0 },
481 {"dotsm", hline3, 0 },
482 {"dotso", hline3, 0 }
483 };
484
485
486 map<docstring, deco_struct> deco_list;
487
488 // sort the table on startup
489 class init_deco_table {
490 public:
init_deco_table()491 init_deco_table() {
492 unsigned const n = sizeof(deco_table) / sizeof(deco_table[0]);
493 for (named_deco_struct * p = deco_table; p != deco_table + n; ++p) {
494 deco_struct d;
495 d.data = p->data;
496 d.angle = p->angle;
497 deco_list[from_ascii(p->name)] = d;
498 }
499 }
500 };
501
502 static init_deco_table dummy;
503
504
search_deco(docstring const & name)505 deco_struct const * search_deco(docstring const & name)
506 {
507 map<docstring, deco_struct>::const_iterator p = deco_list.find(name);
508 return p == deco_list.end() ? 0 : &(p->second);
509 }
510
511
512 } // namespace
513
514
mathed_font_em(FontInfo const & font)515 int mathed_font_em(FontInfo const & font)
516 {
517 return theFontMetrics(font).em();
518 }
519
520
mathed_font_x_height(FontInfo const & font)521 int mathed_font_x_height(FontInfo const & font)
522 {
523 return theFontMetrics(font).ascent('x');
524 }
525
526 /* The math units. Quoting TeX by Topic, p.205:
527 *
528 * Spacing around mathematical objects is measured in mu units. A mu
529 * is 1/18th part of \fontdimen6 of the font in family 2 in the
530 * current style, the ‘quad’ value of the symbol font.
531 *
532 * A \thickmuskip (default value in plain TeX: 5mu plus 5mu) is
533 * inserted around (binary) relations, except where these are preceded
534 * or followed by other relations or punctuation, and except if they
535 * follow an open, or precede a close symbol.
536 *
537 * A \medmuskip (default value in plain TeX: 4mu plus 2mu minus 4mu)
538 * is put around binary operators.
539 *
540 * A \thinmuskip (default value in plain TeX: 3mu) follows after
541 * punctuation, and is put around inner objects, except where these
542 * are followed by a close or preceded by an open symbol, and except
543 * if the other object is a large operator or a binary relation.
544 *
545 * See the file MathClass.cpp for a formal implementation of the rules
546 * above.
547 */
548
mathed_mu(FontInfo const & font,double mu)549 int mathed_mu(FontInfo const & font, double mu)
550 {
551 MetricsBase mb(nullptr, font);
552 return Length(mu, Length::MU).inPixels(mb);
553 }
554
mathed_thinmuskip(FontInfo const & font)555 int mathed_thinmuskip(FontInfo const & font) { return mathed_mu(font, 3.0); }
mathed_medmuskip(FontInfo const & font)556 int mathed_medmuskip(FontInfo const & font) { return mathed_mu(font, 4.0); }
mathed_thickmuskip(FontInfo const & font)557 int mathed_thickmuskip(FontInfo const & font) { return mathed_mu(font, 5.0); }
558
559
mathed_char_width(FontInfo const & font,char_type c)560 int mathed_char_width(FontInfo const & font, char_type c)
561 {
562 return theFontMetrics(font).width(c);
563 }
564
565
mathed_char_kerning(FontInfo const & font,char_type c)566 int mathed_char_kerning(FontInfo const & font, char_type c)
567 {
568 frontend::FontMetrics const & fm = theFontMetrics(font);
569 return max(0, fm.rbearing(c) - fm.width(c));
570 }
571
572
mathed_string_dim(FontInfo const & font,docstring const & s,Dimension & dim)573 void mathed_string_dim(FontInfo const & font,
574 docstring const & s,
575 Dimension & dim)
576 {
577 frontend::FontMetrics const & fm = theFontMetrics(font);
578 dim.asc = 0;
579 dim.des = 0;
580 for (docstring::const_iterator it = s.begin();
581 it != s.end();
582 ++it) {
583 dim.asc = max(dim.asc, fm.ascent(*it));
584 dim.des = max(dim.des, fm.descent(*it));
585 }
586 dim.wid = fm.width(s);
587 }
588
589
mathed_string_width(FontInfo const & font,docstring const & s)590 int mathed_string_width(FontInfo const & font, docstring const & s)
591 {
592 return theFontMetrics(font).width(s);
593 }
594
595
mathed_draw_deco(PainterInfo & pi,int x,int y,int w,int h,docstring const & name)596 void mathed_draw_deco(PainterInfo & pi, int x, int y, int w, int h,
597 docstring const & name)
598 {
599 if (name == ".") {
600 pi.pain.line(x + w/2, y, x + w/2, y + h,
601 Color_cursor, Painter::line_onoffdash);
602 return;
603 }
604
605 deco_struct const * mds = search_deco(name);
606 if (!mds) {
607 lyxerr << "Deco was not found. Programming error?" << endl;
608 lyxerr << "name: '" << to_utf8(name) << "'" << endl;
609 return;
610 }
611
612 int const n = (w < h) ? w : h;
613 int const r = mds->angle;
614 double const * d = mds->data;
615
616 if (h > 70 && (name == "(" || name == ")"))
617 d = parenthHigh;
618
619 Matrix mt(r, w, h);
620 Matrix sqmt(r, n, n);
621
622 if (r > 0 && r < 3)
623 y += h;
624
625 if (r >= 2)
626 x += w;
627
628 for (int i = 0; d[i]; ) {
629 int code = int(d[i++]);
630 if (code & 1) { // code == 1 || code == 3 || code == 5
631 double xx = d[i++];
632 double yy = d[i++];
633 double x2 = d[i++];
634 double y2 = d[i++];
635 if (code == 3)
636 sqmt.transform(xx, yy);
637 else
638 mt.transform(xx, yy);
639 mt.transform(x2, y2);
640 pi.pain.line(
641 int(x + xx + 0.5), int(y + yy + 0.5),
642 int(x + x2 + 0.5), int(y + y2 + 0.5),
643 pi.base.font.color());
644 if (code == 5) { // thicker, but rounded
645 pi.pain.line(
646 int(x + xx + 0.5+1), int(y + yy + 0.5-1),
647 int(x + x2 + 0.5-1), int(y + y2 + 0.5-1),
648 pi.base.font.color());
649 pi.pain.line(
650 int(x + xx + 0.5+1), int(y + yy + 0.5+1),
651 int(x + x2 + 0.5-1), int(y + y2 + 0.5+1),
652 pi.base.font.color());
653 }
654 } else {
655 int xp[32];
656 int yp[32];
657 int const n = int(d[i++]);
658 for (int j = 0; j < n; ++j) {
659 double xx = d[i++];
660 double yy = d[i++];
661 // lyxerr << ' ' << xx << ' ' << yy << ' ';
662 if (code == 4)
663 sqmt.transform(xx, yy);
664 else
665 mt.transform(xx, yy);
666 xp[j] = int(x + xx + 0.5);
667 yp[j] = int(y + yy + 0.5);
668 // lyxerr << "P[" << j ' ' << xx << ' ' << yy << ' ' << x << ' ' << y << ']';
669 }
670 pi.pain.lines(xp, yp, n, pi.base.font.color());
671 }
672 }
673 }
674
675
mathedSymbolDim(MetricsBase & mb,Dimension & dim,latexkeys const * sym)676 void mathedSymbolDim(MetricsBase & mb, Dimension & dim, latexkeys const * sym)
677 {
678 LASSERT((bool)sym, return);
679 //lyxerr << "metrics: symbol: '" << sym->name
680 // << "' in font: '" << sym->inset
681 // << "' drawn as: '" << sym->draw
682 // << "'" << endl;
683
684 bool const italic_upcase_greek = sym->inset == "cmr" &&
685 sym->extra == "mathalpha" &&
686 mb.fontname == "mathit";
687 std::string const font = italic_upcase_greek ? "cmm" : sym->inset;
688 Changer dummy = mb.changeFontSet(font);
689 mathed_string_dim(mb.font, sym->draw, dim);
690 }
691
692
mathedSymbolDraw(PainterInfo & pi,int x,int y,latexkeys const * sym)693 void mathedSymbolDraw(PainterInfo & pi, int x, int y, latexkeys const * sym)
694 {
695 LASSERT((bool)sym, return);
696 //lyxerr << "drawing: symbol: '" << sym->name
697 // << "' in font: '" << sym->inset
698 // << "' drawn as: '" << sym->draw
699 // << "'" << endl;
700
701 bool const italic_upcase_greek = sym->inset == "cmr" &&
702 sym->extra == "mathalpha" &&
703 pi.base.fontname == "mathit";
704 std::string const font = italic_upcase_greek ? "cmm" : sym->inset;
705
706 Changer dummy = pi.base.changeFontSet(font);
707 pi.draw(x, y, sym->draw);
708 }
709
710
metricsStrRedBlack(MetricsInfo & mi,Dimension & dim,docstring const & str)711 void metricsStrRedBlack(MetricsInfo & mi, Dimension & dim, docstring const & str)
712 {
713 FontInfo font = mi.base.font;
714 augmentFont(font, "mathnormal");
715 mathed_string_dim(font, str, dim);
716 }
717
718
drawStrRed(PainterInfo & pi,int x,int y,docstring const & str)719 void drawStrRed(PainterInfo & pi, int x, int y, docstring const & str)
720 {
721 FontInfo f = pi.base.font;
722 augmentFont(f, "mathnormal");
723 f.setColor(Color_latex);
724 pi.pain.text(x, y, str, f);
725 }
726
727
drawStrBlack(PainterInfo & pi,int x,int y,docstring const & str)728 void drawStrBlack(PainterInfo & pi, int x, int y, docstring const & str)
729 {
730 FontInfo f = pi.base.font;
731 augmentFont(f, "mathnormal");
732 f.setColor(Color_foreground);
733 pi.pain.text(x, y, str, f);
734 }
735
736
math_font_max_dim(FontInfo const & font,int & asc,int & des)737 void math_font_max_dim(FontInfo const & font, int & asc, int & des)
738 {
739 frontend::FontMetrics const & fm = theFontMetrics(font);
740 asc = fm.maxAscent();
741 des = fm.maxDescent();
742 }
743
744
745 struct fontinfo {
746 string cmd_;
747 FontFamily family_;
748 FontSeries series_;
749 FontShape shape_;
750 ColorCode color_;
751 };
752
753
754 FontFamily const inh_family = INHERIT_FAMILY;
755 FontSeries const inh_series = INHERIT_SERIES;
756 FontShape const inh_shape = INHERIT_SHAPE;
757
758
759 // mathnormal should be the first, otherwise the fallback further down
760 // does not work
761 fontinfo fontinfos[] = {
762 // math fonts
763 // Color_math determines which fonts are math (see isMathFont)
764 {"mathnormal", ROMAN_FAMILY, MEDIUM_SERIES,
765 ITALIC_SHAPE, Color_math},
766 {"mathbf", inh_family, BOLD_SERIES,
767 inh_shape, Color_math},
768 {"mathcal", CMSY_FAMILY, inh_series,
769 inh_shape, Color_math},
770 {"mathfrak", EUFRAK_FAMILY, inh_series,
771 inh_shape, Color_math},
772 {"mathrm", ROMAN_FAMILY, inh_series,
773 UP_SHAPE, Color_math},
774 {"mathsf", SANS_FAMILY, inh_series,
775 inh_shape, Color_math},
776 {"mathbb", MSB_FAMILY, inh_series,
777 inh_shape, Color_math},
778 {"mathtt", TYPEWRITER_FAMILY, inh_series,
779 inh_shape, Color_math},
780 {"mathit", inh_family, inh_series,
781 ITALIC_SHAPE, Color_math},
782 {"mathscr", RSFS_FAMILY, inh_series,
783 inh_shape, Color_math},
784 {"cmex", CMEX_FAMILY, inh_series,
785 inh_shape, Color_math},
786 {"cmm", CMM_FAMILY, inh_series,
787 inh_shape, Color_math},
788 {"cmr", CMR_FAMILY, inh_series,
789 inh_shape, Color_math},
790 {"cmsy", CMSY_FAMILY, inh_series,
791 inh_shape, Color_math},
792 {"eufrak", EUFRAK_FAMILY, inh_series,
793 inh_shape, Color_math},
794 {"msa", MSA_FAMILY, inh_series,
795 inh_shape, Color_math},
796 {"msb", MSB_FAMILY, inh_series,
797 inh_shape, Color_math},
798 {"stmry", STMARY_FAMILY, inh_series,
799 inh_shape, Color_math},
800 {"wasy", WASY_FAMILY, inh_series,
801 inh_shape, Color_math},
802 {"esint", ESINT_FAMILY, inh_series,
803 inh_shape, Color_math},
804
805 // Text fonts
806 {"text", inh_family, inh_series,
807 inh_shape, Color_foreground},
808 {"textbf", inh_family, BOLD_SERIES,
809 inh_shape, Color_foreground},
810 {"textit", inh_family, inh_series,
811 ITALIC_SHAPE, Color_foreground},
812 {"textmd", inh_family, MEDIUM_SERIES,
813 inh_shape, Color_foreground},
814 {"textnormal", inh_family, inh_series,
815 UP_SHAPE, Color_foreground},
816 {"textrm", ROMAN_FAMILY,
817 inh_series, UP_SHAPE,Color_foreground},
818 {"textsc", inh_family, inh_series,
819 SMALLCAPS_SHAPE, Color_foreground},
820 {"textsf", SANS_FAMILY, inh_series,
821 inh_shape, Color_foreground},
822 {"textsl", inh_family, inh_series,
823 SLANTED_SHAPE, Color_foreground},
824 {"texttt", TYPEWRITER_FAMILY, inh_series,
825 inh_shape, Color_foreground},
826 {"textup", inh_family, inh_series,
827 UP_SHAPE, Color_foreground},
828
829 // TIPA support
830 {"textipa", inh_family, inh_series,
831 inh_shape, Color_foreground},
832
833 // mhchem support
834 {"ce", inh_family, inh_series,
835 inh_shape, Color_foreground},
836 {"cf", inh_family, inh_series,
837 inh_shape, Color_foreground},
838
839 // LyX internal usage
840 {"lyxtex", inh_family, inh_series,
841 UP_SHAPE, Color_latex},
842 // FIXME: The following two don't work on OS X, since the Symbol font
843 // uses a different encoding, and is therefore disabled in
844 // FontLoader::available().
845 {"lyxsymbol", SYMBOL_FAMILY, inh_series,
846 inh_shape, Color_math},
847 {"lyxboldsymbol", SYMBOL_FAMILY, BOLD_SERIES,
848 inh_shape, Color_math},
849 {"lyxblacktext", ROMAN_FAMILY, MEDIUM_SERIES,
850 UP_SHAPE, Color_foreground},
851 {"lyxnochange", inh_family, inh_series,
852 inh_shape, Color_foreground},
853 {"lyxfakebb", TYPEWRITER_FAMILY, BOLD_SERIES,
854 UP_SHAPE, Color_math},
855 {"lyxfakecal", SANS_FAMILY, MEDIUM_SERIES,
856 ITALIC_SHAPE, Color_math},
857 {"lyxfakefrak", ROMAN_FAMILY, BOLD_SERIES,
858 ITALIC_SHAPE, Color_math}
859 };
860
861
lookupFont(string const & name)862 fontinfo * lookupFont(string const & name)
863 {
864 //lyxerr << "searching font '" << name << "'" << endl;
865 int const n = sizeof(fontinfos) / sizeof(fontinfo);
866 for (int i = 0; i < n; ++i)
867 if (fontinfos[i].cmd_ == name) {
868 //lyxerr << "found '" << i << "'" << endl;
869 return fontinfos + i;
870 }
871 return 0;
872 }
873
874
searchFont(string const & name)875 fontinfo * searchFont(string const & name)
876 {
877 fontinfo * f = lookupFont(name);
878 return f ? f : fontinfos;
879 // this should be mathnormal
880 //return searchFont("mathnormal");
881 }
882
883
isFontName(string const & name)884 bool isFontName(string const & name)
885 {
886 return lookupFont(name);
887 }
888
889
isMathFont(string const & name)890 bool isMathFont(string const & name)
891 {
892 fontinfo * f = lookupFont(name);
893 return f && f->color_ == Color_math;
894 }
895
896
isTextFont(string const & name)897 bool isTextFont(string const & name)
898 {
899 fontinfo * f = lookupFont(name);
900 return f && f->color_ == Color_foreground;
901 }
902
903
getFont(string const & name)904 FontInfo getFont(string const & name)
905 {
906 FontInfo font;
907 augmentFont(font, name);
908 return font;
909 }
910
911
fakeFont(string const & orig,string const & fake)912 void fakeFont(string const & orig, string const & fake)
913 {
914 fontinfo * forig = searchFont(orig);
915 fontinfo * ffake = searchFont(fake);
916 if (forig && ffake) {
917 forig->family_ = ffake->family_;
918 forig->series_ = ffake->series_;
919 forig->shape_ = ffake->shape_;
920 forig->color_ = ffake->color_;
921 } else {
922 lyxerr << "Can't fake font '" << orig << "' with '"
923 << fake << "'" << endl;
924 }
925 }
926
927
augmentFont(FontInfo & font,string const & name)928 void augmentFont(FontInfo & font, string const & name)
929 {
930 static bool initialized = false;
931 if (!initialized) {
932 initialized = true;
933 // fake fonts if necessary
934 if (!theFontLoader().available(getFont("mathfrak")))
935 fakeFont("mathfrak", "lyxfakefrak");
936 if (!theFontLoader().available(getFont("mathcal")))
937 fakeFont("mathcal", "lyxfakecal");
938 }
939 fontinfo * info = searchFont(name);
940 if (info->family_ != inh_family)
941 font.setFamily(info->family_);
942 if (info->series_ != inh_series)
943 font.setSeries(info->series_);
944 if (info->shape_ != inh_shape)
945 font.setShape(info->shape_);
946 if (info->color_ != Color_none)
947 font.setColor(info->color_);
948 }
949
950
isAlphaSymbol(MathAtom const & at)951 bool isAlphaSymbol(MathAtom const & at)
952 {
953 if (at->asCharInset() ||
954 (at->asSymbolInset() &&
955 at->asSymbolInset()->isOrdAlpha()))
956 return true;
957
958 if (at->asFontInset()) {
959 MathData const & ar = at->asFontInset()->cell(0);
960 for (size_t i = 0; i < ar.size(); ++i) {
961 if (!(ar[i]->asCharInset() ||
962 (ar[i]->asSymbolInset() &&
963 ar[i]->asSymbolInset()->isOrdAlpha())))
964 return false;
965 }
966 return true;
967 }
968 return false;
969 }
970
971
asString(MathData const & ar)972 docstring asString(MathData const & ar)
973 {
974 odocstringstream os;
975 otexrowstream ots(os);
976 WriteStream ws(ots);
977 ws << ar;
978 return os.str();
979 }
980
981
asArray(docstring const & str,MathData & ar,Parse::flags pf)982 void asArray(docstring const & str, MathData & ar, Parse::flags pf)
983 {
984 // If the QUIET flag is set, we are going to parse for either
985 // a paste operation or a macro definition. We try to do the
986 // right thing in all cases.
987
988 bool quiet = pf & Parse::QUIET;
989 bool macro = pf & Parse::MACRODEF;
990 if ((str.size() == 1 && quiet) || (!mathed_parse_cell(ar, str, pf) && quiet && !macro))
991 mathed_parse_cell(ar, str, pf | Parse::VERBATIM);
992 }
993
994
asString(InsetMath const & inset)995 docstring asString(InsetMath const & inset)
996 {
997 odocstringstream os;
998 otexrowstream ots(os);
999 WriteStream ws(ots);
1000 inset.write(ws);
1001 return os.str();
1002 }
1003
1004
asString(MathAtom const & at)1005 docstring asString(MathAtom const & at)
1006 {
1007 odocstringstream os;
1008 otexrowstream ots(os);
1009 WriteStream ws(ots);
1010 at->write(ws);
1011 return os.str();
1012 }
1013
1014
axis_height(MetricsBase & mb)1015 int axis_height(MetricsBase & mb)
1016 {
1017 Changer dummy = mb.changeFontSet("mathnormal");
1018 return theFontMetrics(mb.font).ascent('-') - 1;
1019 }
1020
1021
validate_math_word(LaTeXFeatures & features,docstring const & word)1022 void validate_math_word(LaTeXFeatures & features, docstring const & word)
1023 {
1024 MathWordList const & words = mathedWordList();
1025 MathWordList::const_iterator it = words.find(word);
1026 if (it != words.end()) {
1027 string const req = it->second.requires;
1028 if (!req.empty())
1029 features.require(req);
1030 }
1031 }
1032
1033
1034 } // namespace lyx
1035