]> git.lyx.org Git - lyx.git/blob - src/mathed/InsetMathFrac.cpp
Correct computation of math font size
[lyx.git] / src / mathed / InsetMathFrac.cpp
1 /**
2  * \file InsetMathFracBase.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  * \author Uwe Stöhr
9  *
10  * Full author contact details are available in file CREDITS.
11  */
12
13 #include <config.h>
14
15 #include "InsetMathFrac.h"
16
17 #include "Cursor.h"
18 #include "LaTeXFeatures.h"
19 #include "MathData.h"
20 #include "MathStream.h"
21 #include "MathSupport.h"
22 #include "MetricsInfo.h"
23 #include "TextPainter.h"
24
25 #include "frontends/Painter.h"
26
27 #include "support/lassert.h"
28
29 using namespace std;
30
31
32 namespace lyx {
33
34 /////////////////////////////////////////////////////////////////////
35 //
36 // InsetMathFracBase
37 //
38 /////////////////////////////////////////////////////////////////////
39
40
41 InsetMathFracBase::InsetMathFracBase(Buffer * buf, idx_type ncells)
42         : InsetMathNest(buf, ncells)
43 {}
44
45
46 bool InsetMathFracBase::idxUpDown(Cursor & cur, bool up) const
47 {
48         // If we only have one cell, target = 0, otherwise
49         // target = up ? 0 : 1, since upper cell has idx 0
50         InsetMath::idx_type target = nargs() > 1 ? !up : 0;
51         if (cur.idx() == target)
52                 return false;
53         cur.idx() = target;
54         cur.pos() = cell(target).x2pos(&cur.bv(), cur.x_target());
55         return true;
56 }
57
58
59
60 /////////////////////////////////////////////////////////////////////
61 //
62 // InsetMathFrac
63 //
64 /////////////////////////////////////////////////////////////////////
65
66
67 InsetMathFrac::InsetMathFrac(Buffer * buf, Kind kind, InsetMath::idx_type ncells)
68         : InsetMathFracBase(buf, ncells), kind_(kind)
69 {}
70
71
72 Inset * InsetMathFrac::clone() const
73 {
74         return new InsetMathFrac(*this);
75 }
76
77
78 InsetMathFrac * InsetMathFrac::asFracInset()
79 {
80         return kind_ == ATOP ? 0 : this;
81 }
82
83
84 InsetMathFrac const * InsetMathFrac::asFracInset() const
85 {
86         return kind_ == ATOP ? 0 : this;
87 }
88
89
90 bool InsetMathFrac::idxForward(Cursor & cur) const
91 {
92         InsetMath::idx_type target = 0;
93         if (kind_ == UNIT || (kind_ == UNITFRAC && nargs() == 3)) {
94                 if (nargs() == 3)
95                         target = 0;
96                 else if (nargs() == 2)
97                         target = 1;
98         } else
99                 return false;
100         if (cur.idx() == target)
101                 return false;
102         cur.idx() = target;
103         cur.pos() = cell(target).x2pos(&cur.bv(), cur.x_target());
104         return true;
105 }
106
107
108 bool InsetMathFrac::idxBackward(Cursor & cur) const
109 {
110         InsetMath::idx_type target = 0;
111         if (kind_ == UNIT || (kind_ == UNITFRAC && nargs() == 3)) {
112                 if (nargs() == 3)
113                         target = 2;
114                 else if (nargs() == 2)
115                         target = 0;
116         } else
117                 return false;
118         if (cur.idx() == target)
119                 return false;
120         cur.idx() = target;
121         cur.pos() = cell(target).x2pos(&cur.bv(), cur.x_target());
122         return true;
123 }
124
125
126 MathClass InsetMathFrac::mathClass() const
127 {
128         // Generalized fractions are of inner class (see The TeXbook, p. 292)
129         // But stuff from the unit/nicefrac packages are not real fractions.
130         MathClass mc = MC_ORD;
131         switch (kind_) {
132         case ATOP:
133         case OVER:
134         case FRAC:
135         case DFRAC:
136         case TFRAC:
137         case CFRAC:
138         case CFRACLEFT:
139         case CFRACRIGHT:
140                 mc = MC_INNER;
141                 break;
142         case NICEFRAC:
143         case UNITFRAC:
144         case UNIT:
145                 break;
146         }
147         return mc;
148 }
149
150
151 void InsetMathFrac::metrics(MetricsInfo & mi, Dimension & dim) const
152 {
153         Dimension dim0, dim1, dim2;
154
155         // This could be simplified, including avoiding useless recalculation of
156         // cell metrics
157         if (kind_ == UNIT || (kind_ == UNITFRAC && nargs() == 3)) {
158                 if (nargs() == 1) {
159                         Changer dummy = mi.base.font.changeShape(UP_SHAPE);
160                         cell(0).metrics(mi, dim0);
161                         dim.wid = dim0.width()+ 3;
162                         dim.asc = dim0.asc;
163                         dim.des = dim0.des;
164                 } else if (nargs() == 2) {
165                         cell(0).metrics(mi, dim0);
166                         Changer dummy = mi.base.font.changeShape(UP_SHAPE);
167                         cell(1).metrics(mi, dim1);
168                         dim.wid = dim0.width() + dim1.wid + 5;
169                         dim.asc = max(dim0.asc, dim1.asc);
170                         dim.des = max(dim0.des, dim1.des);
171                 } else {
172                         cell(2).metrics(mi, dim2);
173                         Changer dummy = mi.base.font.changeShape(UP_SHAPE);
174                         Changer dummy2 = mi.base.changeFrac();
175                         cell(0).metrics(mi, dim0);
176                         cell(1).metrics(mi, dim1);
177                         dim.wid = dim0.width() + dim1.wid + dim2.wid + 10;
178                         dim.asc = max(dim2.asc, dim0.height() + 5);
179                         dim.des = max(dim2.des, dim1.height() - 5);
180                 }
181         } else {
182                 // general cell metrics used for \frac
183                 Changer dummy = mi.base.changeFrac();
184                 // FIXME: Exponential blowup
185                 cell(0).metrics(mi, dim0);
186                 cell(1).metrics(mi, dim1);
187                 if (nargs() == 3)
188                         cell(2).metrics(mi, dim2);
189                 // metrics for special fraction types
190                 if (kind_ == NICEFRAC || kind_ == UNITFRAC) {
191                         Changer dummy2 = mi.base.font.changeShape(UP_SHAPE, kind_ == UNITFRAC);
192                         dim.wid = dim0.width() + dim1.wid + 5;
193                         dim.asc = dim0.height() + 5;
194                         dim.des = dim1.height() - 5;
195                 } else {
196                         if (kind_ == CFRAC || kind_ == CFRACLEFT || kind_ == CFRACRIGHT
197                             || kind_ == DFRAC || kind_ == TFRAC) {
198                                 // \cfrac and \dfrac are always in display size
199                                 // \tfrac is in always in text size
200                                 Changer dummy2 = mi.base.font.changeStyle((kind_ == TFRAC)
201                                                                           ? LM_ST_SCRIPT
202                                                                           : LM_ST_DISPLAY);
203                                 cell(0).metrics(mi, dim0);
204                                 cell(1).metrics(mi, dim1);
205                         }
206                         dim.wid = max(dim0.wid, dim1.wid) + 2;
207                         dim.asc = dim0.height() + 2 + 5;
208                         dim.des = dim1.height() + 2 - 5;
209                 }
210         }
211         metricsMarkers(mi, dim);
212 }
213
214
215 void InsetMathFrac::draw(PainterInfo & pi, int x, int y) const
216 {
217         setPosCache(pi, x, y);
218         Dimension const dim = dimension(*pi.base.bv);
219         Dimension const dim0 = cell(0).dimension(*pi.base.bv);
220         if (kind_ == UNIT || (kind_ == UNITFRAC && nargs() == 3)) {
221                 if (nargs() == 1) {
222                         Changer dummy = pi.base.font.changeShape(UP_SHAPE);
223                         cell(0).draw(pi, x + 1, y);
224                 } else if (nargs() == 2) {
225                         cell(0).draw(pi, x + 1, y);
226                         Changer dummy = pi.base.font.changeShape(UP_SHAPE);
227                         cell(1).draw(pi, x + dim0.width() + 5, y);
228                 } else {
229                         cell(2).draw(pi, x + 1, y);
230                         Changer dummy = pi.base.font.changeShape(UP_SHAPE);
231                         Changer dummy2 = pi.base.changeFrac();
232                         Dimension const dim1 = cell(1).dimension(*pi.base.bv);
233                         Dimension const dim2 = cell(2).dimension(*pi.base.bv);
234                         int xx = x + dim2.wid + 5;
235                         cell(0).draw(pi, xx + 2, 
236                                          y - dim0.des - 5);
237                         cell(1).draw(pi, xx  + dim0.width() + 5, 
238                                          y + dim1.asc / 2);
239                 }
240         } else {
241                 Changer dummy = pi.base.changeFrac();
242                 Dimension const dim1 = cell(1).dimension(*pi.base.bv);
243                 int m = x + dim.wid / 2;
244                 if (kind_ == NICEFRAC) {
245                         cell(0).draw(pi, x + 2,
246                                         y - dim0.des - 5);
247                         cell(1).draw(pi, x + dim0.width() + 5,
248                                         y + dim1.asc / 2);
249                 } else if (kind_ == UNITFRAC) {
250                         Changer dummy2 = pi.base.font.changeShape(UP_SHAPE);
251                         cell(0).draw(pi, x + 2, y - dim0.des - 5);
252                         cell(1).draw(pi, x + dim0.width() + 5, y + dim1.asc / 2);
253                 } else if (kind_ == FRAC || kind_ == ATOP || kind_ == OVER
254                            || kind_ == TFRAC) {
255                         // tfrac is in always in text size
256                         Changer dummy2 = pi.base.font.changeStyle(LM_ST_SCRIPT,
257                                                                   kind_ == TFRAC);
258                         cell(0).draw(pi, m - dim0.wid / 2, y - dim0.des - 2 - 5);
259                         cell(1).draw(pi, m - dim1.wid / 2, y + dim1.asc + 2 - 5);
260                 } else {
261                         // \cfrac and \dfrac are always in display size
262                         Changer dummy2 = pi.base.font.changeStyle(LM_ST_DISPLAY);
263                         if (kind_ == CFRAC || kind_ == DFRAC)
264                                 cell(0).draw(pi, m - dim0.wid / 2, y - dim0.des - 2 - 5);
265                         else if (kind_ == CFRACLEFT)
266                                 cell(0).draw(pi, x + 2, y - dim0.des - 2 - 5);
267                         else if (kind_ == CFRACRIGHT)
268                                 cell(0).draw(pi, x + dim.wid - dim0.wid - 2,
269                                         y - dim0.des - 2 - 5);
270                         cell(1).draw(pi, m - dim1.wid / 2, y + dim1.asc + 2 - 5);
271                 }
272         }
273         if (kind_ == NICEFRAC || kind_ == UNITFRAC) {
274                 // Diag line:
275                 int xx = x;
276                 if (nargs() == 3)
277                         xx += cell(2).dimension(*pi.base.bv).wid + 5;
278                 pi.pain.line(xx + dim0.wid,
279                                 y + dim.des - 2,
280                                 xx + dim0.wid + 5,
281                                 y - dim.asc + 2, pi.base.font.color());
282         }
283         if (kind_ == FRAC || kind_ == CFRAC || kind_ == CFRACLEFT
284                 || kind_ == CFRACRIGHT || kind_ == DFRAC
285                 || kind_ == TFRAC || kind_ == OVER)
286                 pi.pain.line(x + 1, y - 5,
287                                 x + dim.wid - 2, y - 5, pi.base.font.color());
288         drawMarkers(pi, x, y);
289 }
290
291
292 void InsetMathFrac::metricsT(TextMetricsInfo const & mi, Dimension & dim) const
293 {
294         Dimension dim0, dim1;
295         cell(0).metricsT(mi, dim0);
296         cell(1).metricsT(mi, dim1);
297         dim.wid = max(dim0.width(), dim1.wid);
298         dim.asc = dim0.height() + 1;
299         dim.des = dim1.height();
300 }
301
302
303 void InsetMathFrac::drawT(TextPainter & /*pain*/, int /*x*/, int /*y*/) const
304 {
305         // FIXME: BROKEN!
306         /*
307         Dimension dim;
308         int m = x + dim.width() / 2;
309         cell(0).drawT(pain, m - dim0.width() / 2, y - dim0.des - 1);
310         cell(1).drawT(pain, m - dim1.wid / 2, y + dim1.asc);
311         // ASCII art: ignore niceties
312         if (kind_ == FRAC || kind_ == OVER || kind_ == NICEFRAC || kind_ == UNITFRAC)
313                 pain.horizontalLine(x, y, dim.width());
314         */
315 }
316
317
318 void InsetMathFrac::write(WriteStream & os) const
319 {
320         MathEnsurer ensurer(os);
321         switch (kind_) {
322         case ATOP:
323                 // \\atop is only for compatibility, \\binom is the
324                 // LaTeX2e successor
325                 os << '{' << cell(0) << "\\atop " << cell(1) << '}';
326                 break;
327         case OVER:
328                 // \\over is only for compatibility, normalize this to \\frac
329                 os << "\\frac{" << cell(0) << "}{" << cell(1) << '}';
330                 break;
331         case FRAC:
332         case DFRAC:
333         case TFRAC:
334         case NICEFRAC:
335         case CFRAC:
336         case UNITFRAC:
337                 if (nargs() == 2)
338                         InsetMathNest::write(os);
339                 else
340                         os << "\\unitfrac[" << cell(2) << "]{" << cell(0) << "}{" << cell(1) << '}';
341                 break;
342         case UNIT:
343                 if (nargs() == 2)
344                         os << "\\unit[" << cell(0) << "]{" << cell(1) << '}';
345                 else
346                         os << "\\unit{" << cell(0) << '}';
347                 break;
348         case CFRACLEFT:
349                 os << "\\cfrac[l]{" << cell(0) << "}{" << cell(1) << '}';
350                 break;
351         case CFRACRIGHT:
352                 os << "\\cfrac[r]{" << cell(0) << "}{" << cell(1) << '}';
353                 break;
354         }
355 }
356
357
358 docstring InsetMathFrac::name() const
359 {
360         switch (kind_) {
361         case FRAC:
362                 return from_ascii("frac");
363         case CFRAC:
364         case CFRACLEFT:
365         case CFRACRIGHT:
366                 return from_ascii("cfrac");
367         case DFRAC:
368                 return from_ascii("dfrac");
369         case TFRAC:
370                 return from_ascii("tfrac");
371         case OVER:
372                 return from_ascii("over");
373         case NICEFRAC:
374                 return from_ascii("nicefrac");
375         case UNITFRAC:
376                 return from_ascii("unitfrac");
377         case UNIT:
378                 return from_ascii("unit");
379         case ATOP:
380                 return from_ascii("atop");
381         }
382         // shut up stupid compiler
383         return docstring();
384 }
385
386
387 bool InsetMathFrac::extraBraces() const
388 {
389         return kind_ == ATOP || kind_ == OVER;
390 }
391
392
393 void InsetMathFrac::maple(MapleStream & os) const
394 {
395         if (nargs() != 2) {
396                 // Someone who knows about maple should fix this.
397                 LASSERT(false, return);
398         }
399         os << '(' << cell(0) << ")/(" << cell(1) << ')';
400 }
401
402
403 void InsetMathFrac::mathematica(MathematicaStream & os) const
404 {
405         if (nargs() != 2) {
406                 // Someone who knows about mathematica should fix this.
407                 LASSERT(false, return);
408         }
409         os << '(' << cell(0) << ")/(" << cell(1) << ')';
410 }
411
412
413 void InsetMathFrac::octave(OctaveStream & os) const
414 {
415         if (nargs() != 2) {
416                 // Someone who knows about octave should fix this.
417                 LASSERT(false, return);
418         }
419         os << '(' << cell(0) << ")/(" << cell(1) << ')';
420 }
421
422
423 void InsetMathFrac::mathmlize(MathStream & os) const
424 {
425         switch (kind_) {
426         case ATOP:
427                 os << MTag("mfrac", "linethickeness='0'")
428                    << MTag("mrow") << cell(0) << ETag("mrow")
429                          << MTag("mrow") << cell(1) << ETag("mrow")
430                          << ETag("mfrac");
431                 break;
432
433         // we do not presently distinguish these
434         case OVER:
435         case FRAC:
436         case DFRAC:
437         case TFRAC:
438         case CFRAC:
439         case CFRACLEFT:
440         case CFRACRIGHT:
441                 os << MTag("mfrac")
442                    << MTag("mrow") << cell(0) << ETag("mrow")
443                          << MTag("mrow") << cell(1) << ETag("mrow")
444                          << ETag("mfrac");
445                 break;
446
447         case NICEFRAC:
448                 os << MTag("mfrac", "bevelled='true'")
449                    << MTag("mrow") << cell(0) << ETag("mrow")
450                          << MTag("mrow") << cell(1) << ETag("mrow")
451                          << ETag("mfrac");
452                 break;
453
454         case UNITFRAC:
455                 if (nargs() == 3)
456                         os << cell(2);
457                 os << MTag("mfrac", "bevelled='true'")
458                    << MTag("mrow") << cell(0) << ETag("mrow")
459                          << MTag("mrow") << cell(1) << ETag("mrow")
460                          << ETag("mfrac");
461                 break;
462
463         case UNIT:
464                 // FIXME This is not right, because we still output mi, etc,
465                 // when we output the cell. So we need to prevent that somehow.
466                 if (nargs() == 2)
467                         os << cell(0) 
468                            << MTag("mstyle mathvariant='normal'") 
469                            << cell(1) 
470                            << ETag("mstyle");
471                 else
472                         os << MTag("mstyle mathvariant='normal'") 
473                            << cell(0)
474                            << ETag("mstyle");
475         }
476 }
477
478
479 void InsetMathFrac::htmlize(HtmlStream & os) const
480 {
481         switch (kind_) {
482         case ATOP:
483                 os << MTag("span", "class='frac'")
484                          << MTag("span", "class='numer'") << cell(0) << ETag("span")
485                          << MTag("span", "class='numer'") << cell(1) << ETag("span")
486                          << ETag("span");
487                 break;
488
489         // we do not presently distinguish these
490         case OVER:
491         case FRAC:
492         case DFRAC:
493         case TFRAC:
494         case CFRAC:
495         case CFRACLEFT:
496         case CFRACRIGHT:
497                 os << MTag("span", "class='frac'")
498                          << MTag("span", "class='numer'") << cell(0) << ETag("span")
499                          << MTag("span", "class='denom'") << cell(1) << ETag("span")
500                          << ETag("span");
501                 break;
502
503         case NICEFRAC:
504                 os << cell(0) << '/' << cell(1);
505                 break;
506
507         case UNITFRAC:
508                 if (nargs() == 3)
509                         os << cell(2) << ' ';
510                 os << cell(0) << '/' << cell(1);
511                 break;
512
513         case UNIT:
514                 // FIXME This is not right, because we still output i, etc,
515                 // when we output the cell. So we need to prevent that somehow.
516                 if (nargs() == 2)
517                         os << cell(0) 
518                            << MTag("span") 
519                            << cell(1) 
520                            << ETag("span");
521                 else
522                         os << MTag("span") 
523                            << cell(0)
524                            << ETag("span");
525         }
526 }
527
528
529 void InsetMathFrac::validate(LaTeXFeatures & features) const
530 {
531         if (kind_ == NICEFRAC || kind_ == UNITFRAC || kind_ == UNIT)
532                 features.require("units");
533         if (kind_ == CFRAC || kind_ == CFRACLEFT || kind_ == CFRACRIGHT
534                   || kind_ == DFRAC || kind_ == TFRAC)
535                 features.require("amsmath");
536         if (features.runparams().math_flavor == OutputParams::MathAsHTML)
537                 // CSS adapted from eLyXer
538                 features.addCSSSnippet(
539                         "span.frac{display: inline-block; vertical-align: middle; text-align:center;}\n"
540                         "span.numer{display: block;}\n"
541                         "span.denom{display: block; border-top: thin solid #000040;}");
542         InsetMathNest::validate(features);
543 }
544
545
546 /////////////////////////////////////////////////////////////////////
547 //
548 // InsetMathBinom
549 //
550 /////////////////////////////////////////////////////////////////////
551
552
553 InsetMathBinom::InsetMathBinom(Buffer * buf, Kind kind)
554         : InsetMathFracBase(buf), kind_(kind)
555 {}
556
557
558 Inset * InsetMathBinom::clone() const
559 {
560         return new InsetMathBinom(*this);
561 }
562
563
564 int InsetMathBinom::dw(int height) const
565 {
566         int w = height / 5;
567         if (w > 15)
568                 w = 15;
569         if (w < 6)
570                 w = 6;
571         return w;
572 }
573
574
575 void InsetMathBinom::metrics(MetricsInfo & mi, Dimension & dim) const
576 {
577         Dimension dim0, dim1;
578         Changer dummy =
579                 (kind_ == DBINOM) ? mi.base.font.changeStyle(LM_ST_DISPLAY) :
580                 (kind_ == TBINOM) ? mi.base.font.changeStyle(LM_ST_SCRIPT) :
581                                     mi.base.changeFrac();
582         cell(0).metrics(mi, dim0);
583         cell(1).metrics(mi, dim1);
584         dim.asc = dim0.height() + 4 + 5;
585         dim.des = dim1.height() + 4 - 5;
586         dim.wid = max(dim0.wid, dim1.wid) + 2 * dw(dim.height()) + 4;
587         metricsMarkers2(mi, dim);
588 }
589
590
591 void InsetMathBinom::draw(PainterInfo & pi, int x, int y) const
592 {
593         Dimension const dim = dimension(*pi.base.bv);
594         Dimension const & dim0 = cell(0).dimension(*pi.base.bv);
595         Dimension const & dim1 = cell(1).dimension(*pi.base.bv);
596         // define the binom brackets
597         docstring const bra = kind_ == BRACE ? from_ascii("{") :
598                 kind_ == BRACK ? from_ascii("[") : from_ascii("(");
599         docstring const ket = kind_ == BRACE ? from_ascii("}") :
600                 kind_ == BRACK ? from_ascii("]") : from_ascii(")");
601
602         int m = x + dim.width() / 2;
603         {
604                 Changer dummy =
605                         (kind_ == DBINOM) ? pi.base.font.changeStyle(LM_ST_DISPLAY) :
606                         (kind_ == TBINOM) ? pi.base.font.changeStyle(LM_ST_SCRIPT) :
607                                             pi.base.changeFrac();
608                 cell(0).draw(pi, m - dim0.wid / 2, y - dim0.des - 3 - 5);
609                 cell(1).draw(pi, m - dim1.wid / 2, y + dim1.asc + 3 - 5);
610         }
611         // draw the brackets and the marker
612         mathed_draw_deco(pi, x, y - dim.ascent(), dw(dim.height()),
613                 dim.height(), bra);
614         mathed_draw_deco(pi, x + dim.width() - dw(dim.height()),
615                 y - dim.ascent(), dw(dim.height()), dim.height(), ket);
616         drawMarkers2(pi, x, y);
617 }
618
619
620 bool InsetMathBinom::extraBraces() const
621 {
622         return kind_ == CHOOSE || kind_ == BRACE || kind_ == BRACK;
623 }
624
625
626 void InsetMathBinom::write(WriteStream & os) const
627 {
628         MathEnsurer ensurer(os);
629         switch (kind_) {
630         case BINOM:
631                 os << "\\binom{" << cell(0) << "}{" << cell(1) << '}';
632                 break;
633         case DBINOM:
634                 os << "\\dbinom{" << cell(0) << "}{" << cell(1) << '}';
635                 break;
636         case TBINOM:
637                 os << "\\tbinom{" << cell(0) << "}{" << cell(1) << '}';
638                 break;
639         case CHOOSE:
640                 os << '{' << cell(0) << " \\choose " << cell(1) << '}';
641                 break;
642         case BRACE:
643                 os << '{' << cell(0) << " \\brace " << cell(1) << '}';
644                 break;
645         case BRACK:
646                 os << '{' << cell(0) << " \\brack " << cell(1) << '}';
647                 break;
648         }
649 }
650
651
652 void InsetMathBinom::normalize(NormalStream & os) const
653 {
654         os << "[binom " << cell(0) << ' ' << cell(1) << ']';
655 }
656
657
658 void InsetMathBinom::mathmlize(MathStream & os) const
659 {
660         char ldelim = ' ';
661         char rdelim = ' ';
662         switch (kind_) {
663         case BINOM:
664         case TBINOM:
665         case DBINOM:
666         case CHOOSE:
667                 ldelim = '(';
668                 rdelim = ')';
669                 break;
670         case BRACE:
671                 ldelim = '{';
672                 rdelim = '}';
673                 break;
674         case BRACK:
675                 ldelim = '[';
676                 rdelim = ']';
677                 break;
678         }
679         os << "<mo fence='true' stretchy='true' form='prefix'>" << ldelim << "</mo>"
680            << "<mfrac linethickness='0'>"
681            << cell(0) << cell(1)
682            << "</mfrac>"
683            << "<mo fence='true' stretchy='true' form='postfix'>" << rdelim << "</mo>";
684 }
685
686
687 void InsetMathBinom::htmlize(HtmlStream & os) const
688 {
689         char ldelim = ' ';
690         char rdelim = ' ';
691         switch (kind_) {
692         case BINOM:
693         case TBINOM:
694         case DBINOM:
695         case CHOOSE:
696                 ldelim = '(';
697                 rdelim = ')';
698                 break;
699         case BRACE:
700                 ldelim = '{';
701                 rdelim = '}';
702                 break;
703         case BRACK:
704                 ldelim = '[';
705                 rdelim = ']';
706                 break;
707         }
708         os << MTag("span", "class='binomdelim'") << ldelim << ETag("span") << '\n'
709            << MTag("span", "class='binom'") << '\n'
710            << MTag("span") << cell(0) << ETag("span") << '\n'
711            << MTag("span") << cell(1) << ETag("span") << '\n'
712            << ETag("span") << '\n'
713                  << MTag("span", "class='binomdelim'") << rdelim << ETag("span") << '\n';
714 }
715
716
717 void InsetMathBinom::validate(LaTeXFeatures & features) const
718 {
719         if (features.runparams().isLaTeX()) {
720                 if (kind_ == BINOM)
721                         features.require("binom");
722                 if (kind_ == DBINOM || kind_ == TBINOM)
723                         features.require("amsmath");
724         } else if (features.runparams().math_flavor == OutputParams::MathAsHTML)
725                 features.addCSSSnippet(
726                         "span.binom{display: inline-block; vertical-align: bottom; text-align:center;}\n"
727                         "span.binom span{display: block;}\n"
728                         "span.binomdelim{font-size: 2em;}");
729         InsetMathNest::validate(features);
730 }
731
732
733 } // namespace lyx