Back to index

texmacs  1.0.7.15
concat_math.cpp
Go to the documentation of this file.
00001 
00002 /******************************************************************************
00003 * MODULE     : concat_math.cpp
00004 * DESCRIPTION: Typesetting mathematical markup
00005 * COPYRIGHT  : (C) 1999  Joris van der Hoeven
00006 *******************************************************************************
00007 * This software falls under the GNU general public license version 3 or later.
00008 * It comes WITHOUT ANY WARRANTY WHATSOEVER. For details, see the file LICENSE
00009 * in the root directory or <http://www.gnu.org/licenses/gpl-3.0.html>.
00010 ******************************************************************************/
00011 
00012 #include "concater.hpp"
00013 #include "analyze.hpp"
00014 
00015 /******************************************************************************
00016 * Typesetting special mathematical symbols
00017 ******************************************************************************/
00018 
00019 void
00020 concater_rep::typeset_large (tree t, path ip, int tp, int otp, string prefix) {
00021   if ((N(t) == 1) && is_atomic (t[0])) {
00022     string s= prefix * t[0]->label * ">";
00023     box b= text_box (ip, 0, s, env->fn, env->col);
00024     print (tp, otp, b);
00025     // temporarary: use parameters from group-open class in std-math.syx
00026     // bug: allow hyphenation after ) and before *
00027   }
00028   else if ((N(t) == 2) && is_atomic (t[0]) && is_int (t[1])) {
00029     string s= prefix * t[0]->label * "-" * t[1]->label * ">";
00030     box b= text_box (ip, 0, s, env->fn, env->col);
00031     SI dy= env->fn->yfrac - ((b->y1 + b->y2) >> 1);
00032     box mvb= move_box (ip, b, 0, dy, false, true);
00033     print (STD_ITEM, otp, macro_box (ip, mvb, env->fn));
00034   }
00035   else if ((N(t) >= 2) && is_atomic (t[0])) {
00036     SI y1, y2;
00037     if (N(t) == 2) {
00038       SI l= env->as_length (t[1]) >> 1;
00039       y1= env->fn->yfrac - l;
00040       y2= env->fn->yfrac + l;
00041     }
00042     else {
00043       y1= env->as_length (t[1]);
00044       y2= env->as_length (t[2]);
00045     }
00046     string s= prefix * t[0]->label * ">";
00047     box b= delimiter_box (ip, s, env->fn, env->col, y1, y2);
00048     print (STD_ITEM, otp, b);
00049   }
00050   else typeset_error (t, ip);
00051 }
00052 
00053 void
00054 concater_rep::typeset_bigop (tree t, path ip) {
00055   if ((N(t) == 1) && is_atomic (t[0])) {
00056     space spc= env->fn->spc;
00057     string l= t[0]->label;
00058     string s= "<big-" * l * ">";
00059     bool flag= (!env->math_condensed) && (l != ".");
00060     box b= big_operator_box (ip, s, env->fn, env->col,
00061                           env->display_style? 2: 1);
00062     print (STD_ITEM, OP_BIG, b);
00063     penalty_min (HYPH_PANIC);
00064     if ((l != "int") && (l != "oint")) with_limits (LIMITS_DISPLAY);
00065     if (flag) print (spc);
00066     // temporarary: use parameters from operator-big class in std-math.syx
00067   }
00068   else typeset_error (t, ip);
00069 }
00070 
00071 void
00072 concater_rep::typeset_lprime (tree t, path ip) {
00073   if ((N(t) == 1) && is_atomic (t[0])) {
00074     string s= t[0]->label;
00075     bool flag= (env->fn->type == FONT_TYPE_UNICODE);
00076     if (flag)
00077       for (int i=0; i<N(s); i++)
00078        flag= flag && (s[i] == '\'' || s[i] == '`');
00079     tree old_il;
00080     if (!flag) old_il= env->local_begin_script ();
00081     path sip= descend (ip, 0);
00082     box b1, b2;
00083     b2= typeset_as_concat (env, t[0], sip);
00084     b2= symbol_box (sip, b2, N(t[0]->label));
00085     b2= move_box (sip, b2,
00086                 flag? 0: env->as_length (string ("-0.05fn")),
00087                 flag? env->as_length ("-0.75ex"): 0);
00088     if (!flag) env->local_end_script (old_il);
00089     print (LSUP_ITEM, OP_SKIP, script_box (ip, b1, b2, env->fn));
00090     penalty_max (HYPH_INVALID);
00091   }
00092   else typeset_error (t, ip);
00093 }
00094 
00095 void
00096 concater_rep::typeset_rprime (tree t, path ip) {
00097   if ((N(t) == 1) && is_atomic (t[0])) {
00098     string s= t[0]->label;
00099     bool flag= (env->fn->type == FONT_TYPE_UNICODE);
00100     if (flag)
00101       for (int i=0; i<N(s); i++)
00102        flag= flag && (s[i] == '\'' || s[i] == '`');
00103     tree old_il;
00104     if (!flag) old_il= env->local_begin_script ();
00105     path sip= descend (ip, 0);
00106     box b1, b2;
00107     b2= typeset_as_concat (env, t[0], sip);
00108     b2= symbol_box (sip, b2, N(t[0]->label));
00109     b2= move_box (sip, b2,
00110                 flag? 0: env->as_length (string ("0.05fn")),
00111                 flag? env->as_length ("-0.75ex"): 0);
00112     if (!flag) env->local_end_script (old_il);
00113     penalty_max (HYPH_INVALID);
00114     if (N(a)>0) a[N(a)-1]->limits= false;
00115     print (RSUP_ITEM, OP_SKIP, script_box (ip, b1, b2, env->fn));
00116   }
00117   else typeset_error (t, ip);
00118 }
00119 
00120 /******************************************************************************
00121 * Typesetting scripts
00122 ******************************************************************************/
00123 
00124 void
00125 concater_rep::typeset_long_arrow (tree t, path ip) {
00126   if (N(t) != 2 && N(t) != 3) { typeset_error (t, ip); return; }
00127   tree old_ds= env->local_begin (MATH_DISPLAY, "false");
00128   tree old_mc= env->local_begin (MATH_CONDENSED, "true");
00129   tree old_il= env->local_begin_script ();
00130   box sup_b, sub_b;
00131   if (N(t) >= 2) {
00132     tree old_vp= env->local_begin (MATH_VPOS, "-1");
00133     sup_b= typeset_as_concat (env, t[1], descend (ip, 1));
00134     env->local_end (MATH_VPOS, old_vp);
00135   }
00136   if (N(t) >= 3) {
00137     tree old_vp= env->local_begin (MATH_VPOS, "1");
00138     sub_b= typeset_as_concat (env, t[2], descend (ip, 2));
00139     env->local_end (MATH_VPOS, old_vp);
00140   }
00141   env->local_end_script (old_il);
00142   env->local_end (MATH_CONDENSED, old_mc);
00143   env->local_end (MATH_DISPLAY, old_ds);
00144 
00145   string s= as_string (t[0]);
00146   SI w= sup_b->w();
00147   if (N(t) == 3) w= max (w, sub_b->w());
00148   w += env->fn->wquad;
00149   box arrow= wide_box (decorate (descend (ip, 0)), s, env->fn, env->col, w);
00150 
00151   space spc= env->fn->spc;
00152   if (env->math_condensed) spc= space (spc->min>>3, spc->def>>3, spc->max>>2);
00153   else spc= space (spc->min>>1, spc->def>>1, spc->max);
00154   print (spc);
00155   print (limit_box (ip, arrow, sub_b, sup_b, env->fn, false));
00156   print (spc);
00157 }
00158 
00159 void
00160 concater_rep::typeset_below (tree t, path ip) {
00161   if (N(t) != 2) { typeset_error (t, ip); return; }
00162   box b1= typeset_as_concat (env, t[0], descend (ip, 0));
00163   tree old_ds= env->local_begin (MATH_DISPLAY, "false");
00164   tree old_mc= env->local_begin (MATH_CONDENSED, "true");
00165   tree old_il= env->local_begin_script ();
00166   box b2= typeset_as_concat (env, t[1], descend (ip, 1));
00167   env->local_end_script (old_il);
00168   env->local_end (MATH_CONDENSED, old_mc);
00169   env->local_end (MATH_DISPLAY, old_ds);
00170   print (limit_box (ip, b1, b2, box (), env->fn, false));
00171 }
00172 
00173 void
00174 concater_rep::typeset_above (tree t, path ip) {
00175   if (N(t) != 2) { typeset_error (t, ip); return; }
00176   box b1= typeset_as_concat (env, t[0], descend (ip, 0));
00177   tree old_ds= env->local_begin (MATH_DISPLAY, "false");
00178   tree old_mc= env->local_begin (MATH_CONDENSED, "true");
00179   tree old_il= env->local_begin_script ();
00180   box b2= typeset_as_concat (env, t[1], descend (ip, 1));
00181   env->local_end_script (old_il);
00182   env->local_end (MATH_CONDENSED, old_mc);
00183   env->local_end (MATH_DISPLAY, old_ds);
00184   print (limit_box (ip, b1, box (), b2, env->fn, false));
00185 }
00186 
00187 void
00188 concater_rep::typeset_script (tree t, path ip, bool right) {
00189   if (N(t) != 1) { typeset_error (t, ip); return; }
00190   int type= RSUP_ITEM;
00191   box b1, b2;
00192   tree old_ds= env->local_begin (MATH_DISPLAY, "false");
00193   tree old_mc= env->local_begin (MATH_CONDENSED, "true");
00194   tree old_il= env->local_begin_script ();
00195   if (is_func (t, SUB (right))) {
00196     tree old_vp= env->local_begin (MATH_VPOS, "-1");
00197     b1= typeset_as_concat (env, t[0], descend (ip, 0));
00198     type= right? RSUB_ITEM: LSUB_ITEM;
00199     env->local_end (MATH_VPOS, old_vp);
00200   }
00201   if (is_func (t, SUP (right))) {
00202     tree old_vp= env->local_begin (MATH_VPOS, "1");
00203     b2= typeset_as_concat (env, t[0], descend (ip, 0));
00204     type= right? RSUP_ITEM: LSUP_ITEM;
00205     env->local_end (MATH_VPOS, old_vp);
00206   }
00207   env->local_end_script (old_il);
00208   env->local_end (MATH_CONDENSED, old_mc);
00209   env->local_end (MATH_DISPLAY, old_ds);
00210   if (right) penalty_max (HYPH_INVALID);
00211   a << line_item (type, OP_SKIP,
00212                   script_box (ip, b1, b2, env->fn), HYPH_INVALID);
00213   // do not use print, because of italic space
00214   if (!right) penalty_max (HYPH_INVALID);
00215 }
00216 
00217 /******************************************************************************
00218 * Standard mathematical operations
00219 ******************************************************************************/
00220 
00221 void
00222 concater_rep::typeset_frac (tree t, path ip) {
00223   if (N(t) != 2) { typeset_error (t, ip); return; }
00224   bool disp= env->display_style;
00225   tree old;
00226   if (disp) old= env->local_begin (MATH_DISPLAY, "false");
00227   else old= env->local_begin_script ();
00228   tree old_vp= env->local_begin (MATH_VPOS, "1");
00229   box nom= typeset_as_concat (env, t[0], descend (ip, 0));
00230   env->local_end (MATH_VPOS, "-1");
00231   box den= typeset_as_concat (env, t[1], descend (ip, 1));
00232   env->local_end (MATH_VPOS, old_vp);
00233   font sfn= env->fn;
00234   if (disp) env->local_end (MATH_DISPLAY, old);
00235   else env->local_end_script (old);
00236   print (frac_box (ip, nom, den, env->fn, sfn, env->col));
00237 }
00238 
00239 void
00240 concater_rep::typeset_sqrt (tree t, path ip) {
00241   if (N(t) != 1 && N(t) != 2) { typeset_error (t, ip); return; }
00242   box b= typeset_as_concat (env, t[0], descend (ip, 0));
00243   box ind;
00244   if (N(t)==2) {
00245     bool disp= env->display_style;
00246     tree old;
00247     if (disp) old= env->local_begin (MATH_DISPLAY, "false");
00248     tree old_il= env->local_begin_script ();
00249     ind= typeset_as_concat (env, t[1], descend (ip, 1));
00250     env->local_end_script (old_il);
00251     if (disp) env->local_end (MATH_DISPLAY, old);
00252   }
00253   SI sep= env->fn->sep;
00254   box sqrtb= delimiter_box (decorate_left (ip), "<large-sqrt>",
00255                             env->fn, env->col, b->y1, b->y2+ sep);
00256   print (sqrt_box (ip, b, ind, sqrtb, env->fn, env->col));
00257 }
00258 
00259 void
00260 concater_rep::typeset_wide (tree t, path ip, bool above) {
00261   if (N(t) != 2) { typeset_error (t, ip); return; }
00262   bool wide;
00263   box b= typeset_as_concat (env, t[0], descend (ip, 0));
00264   string s= as_string (t[1]);
00265   if (env->get_string (MATH_FONT) == "adobe" ||
00266       env->fn->type == FONT_TYPE_UNICODE) {
00267     if (s == "^") s= "<hat>";
00268     if (s == "~") s= "<tilde>";
00269   }
00270   if (starts (s, "<wide-")) {
00271     s= "<" * s (6, N(s));
00272     wide= true;
00273   }
00274   else {
00275     wide= (b->w() >= (env->fn->wfn)) || is_func (t, VAR_WIDE);
00276     if (ends (s, "dot>") || (s == "<acute>") ||
00277         (s == "<grave>") || (s == "<abovering>"))
00278       wide= false;
00279   }
00280   if (wide) {
00281     SI w = env->fn->wline;
00282     box wideb;
00283     if ((s == "^") || (s == "<hat>"))
00284       wideb= wide_hat_box   (decorate_middle (ip), b->x1, b->x2, w, env->col);
00285     else if ((s == "~") || (s == "<tilde>"))
00286       wideb= wide_tilda_box (decorate_middle (ip), b->x1, b->x2, w, env->col);
00287     else if (s == "<bar>")
00288       wideb= wide_bar_box   (decorate_middle (ip), b->x1, b->x2, w, env->col);
00289     else if (s == "<vect>")
00290       wideb= wide_vect_box  (decorate_middle (ip), b->x1, b->x2, w, env->col);
00291     else if (s == "<check>")
00292       wideb= wide_check_box (decorate_middle (ip), b->x1, b->x2, w, env->col);
00293     else if (s == "<breve>")
00294       wideb= wide_breve_box (decorate_middle (ip), b->x1, b->x2, w, env->col);
00295     else if (s == "<squnderbrace>" || s == "<squnderbrace*>")
00296       wideb= wide_squbr_box (decorate_middle (ip), b->x1, b->x2, w, env->col);
00297     else if (s == "<sqoverbrace>" || s == "<sqoverbrace*>")
00298       wideb= wide_sqobr_box (decorate_middle (ip), b->x1, b->x2, w, env->col);
00299     else wideb= wide_box (decorate_middle (ip),
00300                           "<rubber-" * s (1, N(s)-1) * ">",
00301                           env->fn, env->col, b->x2- b->x1);
00302     print (wide_box (ip, b, wideb, env->fn, env->fn->sep, above));
00303     if ((s == "<underbrace>") || (s == "<overbrace>") ||
00304         (s == "<squnderbrace>") || (s == "<sqoverbrace>"))
00305       with_limits (LIMITS_ALWAYS);
00306   }
00307   else {
00308     SI sep= above? -env->fn->yx: env->fn->sep;
00309     box wideb= text_box (decorate_middle (ip), 0, s, env->fn, env->col);
00310     if (env->fn->type == FONT_TYPE_UNICODE && b->right_slope () != 0)
00311       wideb= shift_box (decorate_middle (ip), wideb,
00312                         (SI) (-0.5 * b->right_slope () * env->fn->yx), 0);
00313     print (wide_box (ip, b, wideb, env->fn, sep, above));
00314   }
00315 }
00316 
00317 void
00318 concater_rep::typeset_neg (tree t, path ip) {
00319   if (N(t) != 1) { typeset_error (t, ip); return; }
00320   box b= typeset_as_concat (env, t[0], descend (ip, 0));
00321   print (neg_box (ip, b, env->fn, env->col));
00322 }
00323 
00324 /******************************************************************************
00325 * Other markup
00326 ******************************************************************************/
00327 
00328 static string
00329 bracket_color (int nl) {
00330   switch (nl % 3) {
00331   case 0 : return "#662266";
00332   case 1 : return "#226666";
00333   default: return "#663322";
00334   }
00335 }
00336 
00337 static tree
00338 make_large (tree_label l, tree t) {
00339   if (!is_atomic (t)) return tree (l, ".");
00340   string s= t->label;
00341   if (N(s) <= 1) return tree (l, s);
00342   if (s[0] != '<' || s[N(s)-1] != '>' || s == "<nobracket>")
00343     return tree (l, ".");
00344   return tree (l, s (1, N(s)-1));
00345 }
00346 
00347 void
00348 concater_rep::typeset_around (tree t, path ip, bool colored) {
00349   if (colored) {
00350     int nl= env->get_int (MATH_NESTING_LEVEL);
00351     tree old_col= env->local_begin (COLOR, bracket_color (nl));
00352     tree old_nl = env->local_begin (MATH_NESTING_LEVEL, as_string (nl+1));
00353     typeset_around (t, ip, false);
00354     env->local_end (MATH_NESTING_LEVEL, old_nl);
00355     env->local_end (COLOR, old_col);
00356   }
00357   else {
00358     marker (descend (ip, 0));
00359     switch (L(t)) {
00360     case AROUND:
00361       if (N(t) == 3) {
00362         box br1= typeset_as_concat (env, t[0], descend (ip, 0));
00363         print (STD_ITEM, OP_OPENING_BRACKET, br1);
00364         typeset (t[1], descend (ip, 1));
00365         box br2= typeset_as_concat (env, t[2], descend (ip, 2));
00366         print (STD_ITEM, OP_CLOSING_BRACKET, br2);
00367       }
00368       else typeset_error (t, ip);
00369       break;
00370     case VAR_AROUND:
00371       if (N(t) == 3) {
00372         typeset (make_large (LEFT, t[0]),
00373                  decorate_middle (descend (ip, 0)));
00374         typeset (t[1], descend (ip, 1));
00375         typeset (make_large (RIGHT, t[2]),
00376                  decorate_middle (descend (ip, 2)));
00377       }
00378       else typeset_error (t, ip);
00379       break;
00380     case BIG_AROUND:
00381       if (N(t) == 2) {
00382         typeset (make_large (BIG, t[0]),
00383                  decorate_middle (descend (ip, 0)));
00384         typeset (t[1], descend (ip, 1));
00385       }
00386       else typeset_error (t, ip);
00387       break;
00388     default:
00389       break;
00390     }
00391     marker (descend (ip, 1));
00392   }
00393 }
00394 
00395 void
00396 concater_rep::typeset_tree (tree t, path ip) {
00397   if (N(t) == 0) { typeset_error (t, ip); return; }
00398   int i, n= N(t);
00399   array<box> bs(n);
00400   for (i=0; i<n; i++) bs[i]= typeset_as_concat (env, t[i], descend (ip, i));
00401   print (tree_box (ip, bs, env->fn, env->col));
00402 }
00403 
00404 void
00405 concater_rep::typeset_table (tree t, path ip) {
00406   box b= typeset_as_table (env, t, ip);
00407   print (b);
00408 }