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