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