Back to index

texmacs  1.0.7.15
script_boxes.cpp
Go to the documentation of this file.
00001 
00002 /******************************************************************************
00003 * MODULE     : script.cpp
00004 * DESCRIPTION: Script and limit boxes
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 "Boxes/composite.hpp"
00013 #include "Boxes/Composite/italic_correct.hpp"
00014 
00015 /******************************************************************************
00016 * subroutine for scripts
00017 ******************************************************************************/
00018 
00019 static void
00020 finalize_left (path& lip, box sb) {
00021   if (is_accessible (sb->ip)) {
00022     path new_lip= descend (sb->ip->next, 0);
00023     if (path_less (reverse (new_lip), reverse (lip))) lip= new_lip;
00024   }
00025 }
00026 
00027 static void
00028 finalize_right (path& rip, box sb) {
00029   if (is_accessible (sb->ip)) {
00030     path new_rip= descend (sb->ip->next, 1);
00031     if (path_less (reverse (rip), reverse (new_rip))) rip= new_rip;
00032   }
00033 }
00034 
00035 static path
00036 descend_script (path ip1, int side) {
00037   if (is_accessible (ip1)) ip1= ip1->next;
00038   return descend_decode (ip1, side);
00039 }
00040 
00041 static path
00042 descend_script (path ip1, path ip2, int side) {
00043   int i=1;
00044   if (is_accessible (ip2)) {
00045     if (is_decoration (ip1)) i=2;
00046     else {
00047       if ((side == 0) && path_inf (reverse (ip2), reverse (ip1))) i=2;
00048       if ((side == 1) && path_inf (reverse (ip1), reverse (ip2))) i=2;
00049     }
00050   }
00051   if (i==1) return descend_script (ip1, side);
00052   else return descend_script (ip2, side);
00053 }
00054 
00055 static bool
00056 test_script_border (path p, box sb) {
00057   return
00058     is_accessible (sb->ip) &&
00059     (path_up (p) == path_up (reverse (sb->ip)));
00060 }
00061 
00062 /******************************************************************************
00063 * limits
00064 ******************************************************************************/
00065 
00066 struct lim_box_rep: public composite_box_rep {
00067   box  ref;
00068   bool glued;
00069   lim_box_rep (path ip, box ref, box lo, box hi, font fn, bool glued);
00070   operator tree () { return tree (TUPLE, "lim", bs[0]); }
00071   void finalize ();
00072 
00073   path find_box_path (path p, bool& found);
00074   path find_tree_path (path bp);
00075 };
00076 
00077 lim_box_rep::lim_box_rep (path ip, box ref2, box lo, box hi, font fn, bool gl):
00078   composite_box_rep (ip), ref (ref2), glued (gl)
00079 {
00080   SI sep_lo= fn->sep + fn->yshift;
00081   SI sep_hi= fn->sep + (fn->yshift >> 1);
00082   SI X, Y;
00083   insert (ref, 0, 0);
00084   if (!is_nil (lo)) {
00085     SI top= max (lo->y2, fn->y2 * script (fn->size, 1) / fn->size) + sep_lo;
00086     Y= ref->y1;
00087     X= ((SI) (ref->right_slope ()* (Y+top-lo->y1))) + ((ref->x1+ref->x2)>>1);
00088     insert (lo, X- (lo->x2 >> 1), Y-top);
00089     italic_correct (lo);
00090   }
00091   if (!is_nil (hi)) {
00092     SI bot= min (hi->y1, fn->y1 * script (fn->size, 1) / fn->size) - sep_hi;
00093     Y= ref->y2;
00094     X= ((SI) (ref->right_slope ()*(Y+hi->y2-bot))) + ((ref->x1+ref->x2)>>1);
00095     insert (hi, X- (hi->x2 >> 1), Y-bot);
00096     italic_correct (hi);
00097   }
00098   italic_correct (ref);
00099   position ();
00100   italic_restore (ref);
00101   if (!is_nil (lo)) italic_restore (lo);
00102   if (!is_nil (hi)) italic_restore (hi);
00103   left_justify ();
00104   finalize ();
00105 }
00106 
00107 void
00108 lim_box_rep::finalize () {
00109   composite_box_rep::finalize ();
00110   if (glued) {
00111     int i, n= subnr ()- 1;
00112     for (i=1; i<=n; i++) {
00113       finalize_left  (lip, bs[i]);
00114       finalize_right (rip, bs[i]);
00115     }
00116   }
00117 }
00118 
00119 path
00120 lim_box_rep::find_box_path (path p, bool& found) {
00121   if (glued) {
00122     int nr= subnr () - 1;
00123     if (((nr >= 1) && test_script_border (p, bs[1])) ||
00124        ((nr == 2) && test_script_border (p, bs[2])))
00125       {
00126        found= true;
00127        if (last_item (p) == 0) return path (0);
00128        else return path (1);
00129       }
00130   }
00131   return composite_box_rep::find_box_path (p, found);
00132 }
00133 
00134 path
00135 lim_box_rep::find_tree_path (path bp) {
00136   if (glued && is_atom (bp)) {
00137     int nr= subnr()- 1;
00138     if (bp->item == 0) {
00139       if (is_decoration (bs[0]->ip))
00140        return reverse (descend_script (bs[0]->ip, 0));
00141       else return bs[0]->find_tree_path (bs[0]->find_left_box_path ());
00142     }
00143     else {
00144       if (nr == 1) return reverse (descend_script (bs[1]->ip, 1));
00145       else return reverse (descend_script (bs[1]->ip, bs[2]->ip, 1));
00146     }
00147   }
00148   else return composite_box_rep::find_tree_path (bp);
00149 }
00150 
00151 /******************************************************************************
00152 * dummy script boxes
00153 ******************************************************************************/
00154 
00155 struct dummy_script_box_rep: public composite_box_rep {
00156   dummy_script_box_rep (path ip, box b1, box b2, font fn);
00157   operator tree () { return "dummy script"; }
00158   void finalize ();
00159 
00160   path      find_box_path (path p, bool& found);
00161   path      find_tree_path (path bp);
00162 };
00163 
00164 dummy_script_box_rep::dummy_script_box_rep (path ip, box b1, box b2, font fn):
00165   composite_box_rep (ip)
00166 {
00167   SI sep  = fn->sep;
00168   SI lo_y = fn->ysub_lo_base;
00169   SI hi_y = fn->ysup_lo_base;
00170   SI miny2= (fn->y2 - fn->yshift) * script (fn->size, 1) / fn->size;
00171 
00172   if ((!is_nil (b1)) && (!is_nil (b2))) {
00173     SI y= max (b1->y2, miny2);
00174     SI d= lo_y + y + sep - hi_y - b2->y1;
00175     if (d > 0) {
00176       lo_y -= (d>>1);
00177       hi_y += (d>>1);
00178     }
00179   }
00180   if (!is_nil (b1)) {
00181     insert (b1, 0, lo_y);
00182     italic_correct (b1);
00183   }
00184   if (!is_nil (b2)) {
00185     insert (b2, 0, hi_y);
00186     italic_correct (b2);
00187   }
00188   position ();
00189   if (!is_nil (b1)) italic_restore (b1);
00190   if (!is_nil (b2)) italic_restore (b2);
00191   left_justify ();
00192   y1= min (y1, fn->ysub_lo_base);
00193   y2= max (y2, fn->ysup_lo_base + fn->yx);
00194   finalize ();
00195 }
00196 
00197 void
00198 dummy_script_box_rep::finalize () {
00199   int i, n= subnr ();
00200   composite_box_rep::finalize ();
00201   for (i=0; i<n; i++) {
00202     finalize_left  (lip, bs[i]);
00203     finalize_right (rip, bs[i]);
00204   }
00205 }
00206 
00207 path
00208 dummy_script_box_rep::find_box_path (path p, bool& found) {
00209   //cout << "Find " << p << " in " << operator tree () << "\n";
00210   int nr= subnr ();
00211   if (((nr >= 1) && test_script_border (p, bs[0])) ||
00212       ((nr == 2) && test_script_border (p, bs[1])))
00213     {
00214       found= true;
00215       if (last_item (p) == 0) return path (0);
00216       else return path (1);
00217     }
00218   return composite_box_rep::find_box_path (p, found);
00219 }
00220 
00221 path
00222 dummy_script_box_rep::find_tree_path (path bp) {
00223   if (is_atom (bp)) {
00224     int nr= subnr();
00225     if (bp->item == 0) {
00226       if (nr == 1) return reverse (descend_script (bs[0]->ip, 0));
00227       else return reverse (descend_script (bs[0]->ip, bs[1]->ip, 0));
00228     }
00229     else {
00230       if (nr == 1) return reverse (descend_script (bs[0]->ip, 1));
00231       else return reverse (descend_script (bs[0]->ip, bs[1]->ip, 1));
00232     }
00233   }
00234   else return composite_box_rep::find_tree_path (bp);
00235 }
00236 
00237 /******************************************************************************
00238 * side boxes
00239 ******************************************************************************/
00240 
00241 struct side_box_rep: public composite_box_rep {
00242   short nr_left, nr_right;
00243   short id_left, id_right;
00244   side_box_rep (path ip, box r, box l1, box l2, box r1, box r2, font f, int l);
00245   operator tree () {
00246     int i, n= N(bs);
00247     tree t (TUPLE, "side");
00248     for (i=0; i<n; i++) t << ((tree) bs[i]);
00249     return t;
00250   }
00251   void finalize ();
00252 
00253   int       find_child (SI x, SI y, SI delta, bool force);
00254   path      find_box_path (path p, bool& found);
00255   path      find_left_box_path ();
00256   path      find_right_box_path ();
00257   path      find_tree_path (path bp);
00258   cursor    find_cursor (path bp);
00259   selection find_selection (path lbp, path rbp);
00260 
00261   double left_slope () {
00262     return bs[id_left]->left_slope (); }
00263   double right_slope () {
00264     return bs[id_right]->right_slope (); }
00265   SI left_correction () {
00266     return max (0, x1 - sx1(id_left) + bs[id_left]->left_correction ()); }
00267   SI right_correction () {
00268     return max (0, sx2(id_right) + bs[id_right]->right_correction () - x2); }
00269   SI lsub_correction () {
00270     return nr_left==0? bs[0]->lsub_correction (): left_correction (); }
00271   SI lsup_correction () {
00272     return nr_left==0? bs[0]->lsup_correction (): left_correction (); }
00273   SI rsub_correction () {
00274     return nr_right==0? bs[0]->rsub_correction (): right_correction (); }
00275   SI rsup_correction () {
00276     return nr_right==0? bs[0]->rsup_correction (): right_correction (); }
00277 };
00278 
00279 side_box_rep::side_box_rep (
00280   path ip, box ref, box l1, box l2, box r1, box r2, font fn, int level):
00281     composite_box_rep (ip)
00282 {
00283   insert (ref, 0, 0);
00284 
00285   SI sep= fn->sep;
00286   SI sub_lo_base= ref->sub_lo_base (level);
00287   SI sub_hi_lim = ref->sub_hi_lim  (level);
00288   SI sup_lo_lim = ref->sup_lo_lim  (level);
00289   SI sup_lo_base= ref->sup_lo_base (level);
00290   SI sup_hi_lim = ref->sup_hi_lim  (level);
00291   SI shift      = fn->yshift;
00292   SI miny2      = (fn->y2 - fn->yshift) * script (fn->size, 1) / fn->size;
00293   SI lsub= sub_lo_base, lsup= sup_lo_base;
00294   SI rsub= sub_lo_base, rsup= sup_lo_base;
00295 
00296   if (is_nil (l1)) {
00297     if (is_nil (l2)) nr_left= 0;
00298     else {
00299       nr_left= 1;
00300       lsup= max (sup_hi_lim, ref->y2- (shift<<1)) - l2->y2;
00301       if (lsup < sup_lo_base) lsup= sup_lo_base;
00302       if (lsup+ l2->y1 < sup_lo_lim) lsup= sup_lo_lim- l2->y1;
00303     }
00304   }
00305   else {
00306     SI y= max (l1->y2, miny2);
00307     if (lsub + y > sub_hi_lim) lsub= sub_hi_lim- y;
00308     if (is_nil (l2)) nr_left= 1;
00309     else {
00310       nr_left= 2;
00311       lsup= max (sup_hi_lim, ref->y2- (shift<<1)) - l2->y2;
00312       if (lsup < sup_lo_base) lsup= sup_lo_base;
00313       if (lsup+ l2->y1 < sup_lo_lim) lsup= sup_lo_lim- l2->y1;
00314       SI d= lsub + y + sep - lsup - l2->y1;
00315       if (d > 0) {
00316        lsub -= (d>>1);
00317        lsup += (d>>1);
00318       }
00319     }
00320   }
00321 
00322   if (is_nil (r1)) {
00323     if (is_nil (r2)) nr_right= 0;
00324     else {
00325       nr_right= 1;
00326       rsup= max (sup_hi_lim, ref->y2- (shift<<1)) - r2->y2;
00327       if (rsup < sup_lo_base) rsup= sup_lo_base;
00328       if (rsup+ r2->y1 < sup_lo_lim) rsup= sup_lo_lim- r2->y1;
00329     }
00330   }
00331   else {
00332     SI y= max (r1->y2, miny2);
00333     if (rsub + y > sub_hi_lim) rsub= sub_hi_lim- y;
00334     if (is_nil (r2)) nr_right= 1;
00335     else {
00336       nr_right= 2;
00337       rsup= max (sup_hi_lim, ref->y2- (shift<<1)) - r2->y2;
00338       if (rsup < sup_lo_base) rsup= sup_lo_base;
00339       if (rsup+ r2->y1 < sup_lo_lim) rsup= sup_lo_lim- r2->y1;
00340       SI d= rsub + y + sep - rsup - r2->y1;
00341       if (d > 0) {
00342        rsub -= (d>>1);
00343        rsup += (d>>1);
00344       }
00345     }
00346   }
00347 
00348   if (!is_nil (l1)) {
00349     SI dx= l1->right_correction () + ref->lsub_correction ();
00350     insert (l1, -l1->x2- dx, lsub);
00351   }
00352   if (!is_nil (l2)) {
00353     SI dx= l2->right_correction () - ref->lsup_correction ();
00354     insert (l2, -l2->x2- dx, lsup);
00355   }
00356   if (!is_nil (r1)) {
00357     SI dx= r1->left_correction () + ref->rsub_correction ();
00358     insert (r1, ref->x2+ dx, rsub);
00359   }
00360   if (!is_nil (r2)) {
00361     SI dx= r2->left_correction () + ref->rsup_correction ();
00362     insert (r2, ref->x2+ dx, rsup);
00363   }
00364 
00365   position ();
00366   left_justify ();
00367 
00368   int i;
00369   id_left= id_right= 0;
00370   SI lcorr= x1 - sx1(0) + bs[0]->left_correction ();
00371   SI rcorr= sx2(0) + bs[0]->right_correction () - x2;
00372   for (i=1; i<=nr_left; i++) {
00373     SI ltest= x1 - sx1(i) + bs[i]->left_correction ();
00374     if (ltest > lcorr) { id_left= i; lcorr= ltest; }
00375   }
00376   for (; i<=nr_left+nr_right; i++) {
00377     SI rtest= sx2(i) + bs[i]->right_correction () - x2;
00378     if (rtest > rcorr) { id_right= i; rcorr= rtest; }
00379   }
00380 
00381   finalize ();
00382 }
00383 
00384 void
00385 side_box_rep::finalize () {
00386   int i;
00387   composite_box_rep::finalize ();
00388   for (i=1; i<=nr_left+nr_right; i++) {
00389     finalize_left (lip, bs[i]);
00390     finalize_right (rip, bs[i]);
00391   }
00392 }
00393 
00394 int
00395 side_box_rep::find_child (SI x, SI y, SI delta, bool force) {
00396   if (outside (x, delta, x1, x2)) {
00397     int side= box_rep::find_box_path (x, y, delta, force)->item;
00398     if (bs[0]->accessible () || force) {
00399       if ((side == 0) && (nr_left == 0)) return 0;
00400       if ((side == 1) && (nr_right == 0)) return 0;
00401     }
00402     if (is_accessible (ip) || force) return -1;
00403   }
00404   
00405   int i= 0;
00406   int k= nr_left+ 1;
00407   SI  xx, yy;
00408 
00409   if (nr_left>0) {
00410     if (nr_left == 1) xx= sx2(1);
00411     else xx= max (sx2(1), sx2(2));
00412     if ((x<xx) || ((x==xx) && (delta<0))) {
00413       if (bs[1]->accessible () || force) i= 1;
00414       if (nr_left == 2) {
00415        yy= (sy2(1) + sy1(2)) >> 1;
00416        if ((y >= yy) || (bs[1]->decoration () && (!force)))
00417          if (bs[2]->accessible () || force) i= 2;
00418       }
00419       if (i != 0) return i;
00420     }
00421   }
00422 
00423   if (nr_right>0) {
00424     if (nr_right == 1) xx= sx1(k);
00425     else xx= min (sx1(k), sx1(k+1));
00426     if ((x>xx) || ((x==xx) && (delta>=0))) {
00427       if (bs[k]->accessible () || force) i= k;
00428       if (nr_right == 2) {
00429        yy= (sy2(k) + sy1(k+1)) >> 1;
00430        if ((y >= yy) || (bs[k]->decoration () && (!force)))
00431          if (bs[k+1]->accessible () || force) i= k+1;
00432       }
00433       if (i != 0) return i;
00434     }
00435   }
00436 
00437   if (bs[0]->decoration () && (!force)) {
00438     for (i=0; i<(nr_left+nr_right+1); i++)
00439       if (bs[i]->accessible () || force) return i;
00440     return -1;
00441   }
00442 
00443   return 0;
00444 }
00445 
00446 path
00447 side_box_rep::find_box_path (path p, bool& found) {
00448   /*
00449   cout << "Search " << p << " in " << box (this) << " " << ip << "\n";
00450   cout << "  l:\t" << reverse (lip) << "\n";
00451   cout << "  r:\t" << reverse (rip) << "\n";
00452   int i, n= subnr ();
00453   for (i=0; i<n; i++)
00454     cout << "  " << i << ":\t" << reverse (bs[i]->ip) << "\n";
00455   */
00456 
00457   if (((nr_left >= 1) && test_script_border (p, bs[1])) ||
00458       ((nr_left == 2) && test_script_border (p, bs[2])))
00459     {
00460       found= true;
00461       if (last_item (p) == 0) return path (0);
00462       else return path (2);
00463     }
00464   if (((nr_right >= 1) && test_script_border (p, bs[nr_left+ 1])) ||
00465       ((nr_right == 2) && test_script_border (p, bs[nr_left+ 2])))
00466     {
00467       found= true;
00468       if (last_item (p) == 1) return path (1);
00469       else return path (3);
00470     }
00471   return composite_box_rep::find_box_path (p, found);
00472 }
00473 
00474 path
00475 side_box_rep::find_left_box_path () {
00476   if (nr_left == 0) return path (0, bs[0]->find_left_box_path ());
00477   else return path (0);
00478 }
00479 
00480 path
00481 side_box_rep::find_right_box_path () {
00482   if (nr_right == 0) return path (0, bs[0]->find_right_box_path ());
00483   else return path (1);
00484 }
00485 
00486 path
00487 side_box_rep::find_tree_path (path bp) {
00488   if (is_atom (bp)) {
00489     switch (bp->item) {
00490     case 0:
00491       if (nr_left == 0) {
00492        if (is_decoration (bs[0]->ip))
00493          return reverse (descend_script (bs[0]->ip, 0));
00494        else return bs[0]->find_tree_path (bs[0]->find_left_box_path ());
00495       }
00496       if (nr_left == 1) return reverse (descend_script (bs[1]->ip, 0));
00497       return reverse (descend_script (bs[1]->ip, bs[2]->ip, 0));
00498     case 1:
00499       if (nr_right == 0) {
00500        if (is_decoration (bs[0]->ip))
00501          return reverse (descend_script (bs[0]->ip, 1));
00502        else return bs[0]->find_tree_path (bs[0]->find_right_box_path ());
00503       }
00504       if (nr_right == 1) return reverse (descend_script (bs[nr_left+1]->ip,1));
00505       return reverse (descend_script (bs[nr_left+1]->ip, bs[nr_left+2]->ip,1));
00506     case 2:
00507       if (nr_left == 1) return reverse (descend_script (bs[1]->ip, 1));
00508       return reverse (descend_script (bs[1]->ip, bs[2]->ip, 1));
00509     case 3:
00510       if (nr_right == 1) return reverse (descend_script (bs[nr_left+1]->ip,0));
00511       return reverse (descend_script (bs[nr_left+1]->ip, bs[nr_left+2]->ip,0));
00512     }
00513     FAILED ("bad leaf");
00514     return composite_box_rep::find_tree_path (bp);
00515   }
00516   else return composite_box_rep::find_tree_path (bp);
00517 }
00518 
00519 cursor
00520 side_box_rep::find_cursor (path bp) {
00521   if (is_atom (bp) && (bp->item == 2)) {
00522     cursor cu (sx2 (1), 0);
00523     cu->y1= y1; cu->y2= y2;
00524     if (nr_left == 2) cu->ox= max (cu->ox, sx2 (2));
00525     return cu;
00526   }
00527   else if (is_atom (bp) && (bp->item == 3)) {
00528     cursor cu (sx1 (nr_left+ 1), 0);
00529     cu->y1= y1; cu->y2= y2;
00530     if (nr_right == 2) cu->ox= min (cu->ox, sx1 (nr_left+ 2));
00531     return cu;
00532   }
00533   else {
00534     cursor cu= composite_box_rep::find_cursor (bp);
00535     if (is_atom (bp) && (bp->item == 0) && (nr_left != 0)) cu->slope= 0.0;
00536     if (is_atom (bp) && (bp->item == 1) && (nr_right != 0)) cu->slope= 0.0;
00537     return cu;
00538   }
00539 }
00540 
00541 selection
00542 side_box_rep::find_selection (path lbp, path rbp) {
00543   if ((lbp == path (2)) && (!is_atom (rbp)) && (rbp->item == 0))
00544     lbp= path (0, bs[0]->find_left_box_path ());
00545   if ((rbp == path (3)) && (!is_atom (lbp)) && (lbp->item == 0))
00546     rbp= path (0, bs[0]->find_right_box_path ());
00547   return composite_box_rep::find_selection (lbp, rbp);
00548 }
00549 
00550 /******************************************************************************
00551 * box construction routines
00552 ******************************************************************************/
00553 
00554 box
00555 limit_box (path ip, box ref, box lo, box hi, font fn, bool glued) {
00556   return tm_new<lim_box_rep> (ip, ref, lo, hi, fn, glued);
00557 }
00558 
00559 box
00560 script_box (path ip, box b1, box b2, font fn) {
00561   return tm_new<dummy_script_box_rep> (ip, b1, b2, fn);
00562 }
00563 
00564 box
00565 left_script_box (path ip, box ref, box b1, box b2, font fn, int level) {
00566   return tm_new<side_box_rep> (ip, ref, b1, b2, box (), box (), fn, level);
00567 }
00568 
00569 box
00570 right_script_box (path ip, box ref, box b1, box b2, font fn, int level) {
00571   return tm_new<side_box_rep> (ip, ref, box (), box (), b1, b2, fn, level);
00572 }
00573 
00574 box
00575 side_box (path ip, box ref, box l1, box l2, box r1, box r2, font fn, int l) {
00576   return tm_new<side_box_rep> (ip, ref, l1, l2, r1, r2, fn, l);
00577 }