1(***********************************************************************) 2(* *) 3(* HEVEA *) 4(* *) 5(* Luc Maranget, projet PARA, INRIA Rocquencourt *) 6(* *) 7(* Copyright 1998 Institut National de Recherche en Informatique et *) 8(* Automatique. Distributed only by permission. *) 9(* *) 10(***********************************************************************) 11 12let header = "$Id: htmlMath.ml,v 1.49 2012-06-05 14:55:39 maranget Exp $" 13 14 15open Misc 16open Parse_opts 17open HtmlCommon 18open MyStack 19 20 21 22let delay_stack = MyStack.create "delay_stack" 23(* delaying output .... *) 24 25let delay f = 26 if !verbose > 2 then prerr_flags "=> delay" ; 27 push stacks.s_vsize flags.vsize ; 28 flags.vsize <- 0; 29 push delay_stack f ; 30 open_block DELAY "" ; 31 if !verbose > 2 then prerr_flags "<= delay" 32 33let flush x = 34 if !verbose > 2 then 35 prerr_flags ("=> flush arg is ``"^string_of_int x^"''"); 36 try_close_block DELAY ; 37 let ps,_,pout = pop_out out_stack in 38 if ps <> DELAY then 39 raise (Misc.Fatal ("html: Flush attempt on: "^string_of_block ps)) ; 40 let mods = as_envs !cur_out.active !cur_out.pending in 41 do_close_mods () ; 42 let old_out = !cur_out in 43 cur_out := pout ; 44 let f = pop delay_stack in 45 f x ; 46 Out.copy old_out.out !cur_out.out ; 47 flags.empty <- false ; flags.blank <- false ; 48 !cur_out.pending <- mods ; 49 flags.vsize <- max (pop stacks.s_vsize) flags.vsize ; 50 if !verbose > 2 then 51 prerr_flags "<= flush" 52 53(* put functions *) 54 55let put = HtmlCommon.put 56and put_char = HtmlCommon.put_char 57 58let put_in_math s = 59 if flags.in_pre && !pedantic then 60 put s 61 else begin 62 put "<i>"; 63 put s; 64 put "</i>"; 65 flags.empty <- false; flags.blank <- false; 66 end 67 68(*----------*) 69(* DISPLAYS *) 70(*----------*) 71 72let display_cell_arg tdarg = 73 let arg = 74 if !displayverb then 75 "class=\"vdcell\"" 76 else 77 "class=\"dcell\"" in 78 match tdarg with 79 | "" -> arg 80 | _ -> arg ^ " " ^ tdarg 81 82let open_display_cell tdarg = open_block TD (display_cell_arg tdarg) 83 84let begin_item_display f is_freeze = 85 if !verbose > 2 then begin 86 Printf.fprintf stderr "begin_item_display: ncols=%d empty=%s" flags.ncols (sbool flags.empty) ; 87 prerr_newline () 88 end ; 89 open_display_cell "" ; 90 open_block DFLOW "" ; 91 if is_freeze then freeze f 92 93 94and end_item_display () = 95 let f,is_freeze = pop_freeze () in 96 let _ = close_flow_loc check_empty DFLOW in 97 if close_flow_loc check_empty TD then 98 flags.ncols <- flags.ncols + 1; 99 if !verbose > 2 then begin 100 Printf.fprintf stderr "end_item_display: ncols=%d stck: " flags.ncols; 101 pretty_stack out_stack 102 end; 103 flags.vsize,f,is_freeze 104 105(******************************************************** 106 * * 107 * To open display with vertical alignment arguments * 108 * * 109*********************************************************) 110 111let open_display_varg centering varg = 112 if !verbose > 2 then begin 113 Printf.fprintf stderr "open_display: " 114 end ; 115 try_open_display () ; 116 open_block (DISPLAY centering) varg ; 117 open_display_cell "" ; 118 open_block DFLOW "" ; 119 if !verbose > 2 then begin 120 pretty_cur !cur_out ; 121 prerr_endline "" 122 end 123 124 125(* 126 let open_display_varg_harg centering varg harg = 127 if !verbose > 2 then begin 128 Printf.fprintf stderr "open_display: " 129 end ; 130 try_open_display () ; 131 open_block (DISPLAY centering) (varg^harg); 132 open_display_cell "" ; 133 open_block DFLOW "" ; 134 if !verbose > 2 then begin 135 pretty_cur !cur_out ; 136 prerr_endline "" 137 end 138*) 139 140let open_display centering = open_display_varg centering "style=\"vertical-align:middle\"" 141 142(* argument force forces the display structure, 143 when false, the TABLE/TR/TD may be spared in two situation 144 1. No display cell at all (n=0) 145 2. One display cell, one empty cell *) 146let close_display force = 147 if !verbose > 2 then begin 148 prerr_flags "=> close_display " ; pretty_stack out_stack ; 149 Out.debug stderr !cur_out.out 150 end ; 151 if not (flush_freeze ()) then begin 152 close_flow DFLOW ; 153 if !verbose > 3 then begin 154 Printf.eprintf "Just closed DFLOW " ; pretty_stack out_stack ; 155 Out.debug stderr !cur_out.out 156 end ; 157 let n = flags.ncols in 158 if !verbose > 2 then 159 Printf.fprintf stderr "=> close_display, ncols=%d\n" n ; 160 if (n = 0 && not flags.blank && not force) then begin 161 if !verbose > 2 then begin 162 prerr_string "No Display n=0" ; 163 (Out.debug stderr !cur_out.out); 164 prerr_endline "" 165 end; 166 let active = !cur_out.active and pending = !cur_out.pending in 167 do_close_mods () ; 168 let ps,_,_pout = pop_out out_stack in 169 if ps <> TD then 170 failclose "close_display" ps TD ; 171 do_close_mods () ; 172 try_close_block TD ; 173 let ps,_,ppout = pop_out out_stack in 174 begin match ps with 175 | DISPLAY _ -> () 176 | _ -> 177 failclose "close_display" ps (DISPLAY false) 178 end; 179 try_close_block ps ; 180 let old_out = !cur_out in 181 cur_out := ppout ; 182 do_close_mods () ; 183 Out.copy old_out.out !cur_out.out ; 184 flags.empty <- false ; flags.blank <- false ; 185 !cur_out.pending <- as_envs active pending 186 end else if (n=1 && flags.blank && not force) then begin 187 if !verbose > 2 then begin 188 prerr_string "No display n=1"; 189 (Out.debug stderr !cur_out.out); 190 prerr_endline "" ; 191 end; 192 close_flow FORGET ; 193 let active = !cur_out.active and pending = !cur_out.pending in 194 let ps,_,pout = pop_out out_stack in 195 begin match ps with 196 | DISPLAY _ -> () 197 | _ -> 198 failclose "close_display" ps (DISPLAY false) 199 end ; 200 try_close_block ps ; 201 let old_out = !cur_out in 202 cur_out := pout ; 203 do_close_mods () ; 204 Out.copy_no_tag old_out.out !cur_out.out ; 205 flags.empty <- false ; flags.blank <- false ; 206 !cur_out.pending <- as_envs active pending 207 end else begin 208 if !verbose > 2 then begin 209 prerr_string ("One Display n="^string_of_int n) ; 210 (Out.debug stderr !cur_out.out); 211 prerr_endline "" 212 end; 213 flags.empty <- flags.blank ; 214 close_flow TD ; 215 close_flow (DISPLAY false) 216 end ; 217 try_close_display () 218 end ; 219 if !verbose > 2 then 220 prerr_flags ("<= close_display") 221 222 223let do_item_display force = 224 if !verbose > 2 then begin 225 prerr_endline ("Item Display ncols="^string_of_int flags.ncols^" table_inside="^sbool flags.table_inside^", force="^sbool force) ; 226 pretty_stack out_stack 227 end ; 228 if (force && not flags.empty) || flags.table_inside then begin 229 let f,is_freeze = pop_freeze () in 230 push stacks.s_saved_inside 231 (pop stacks.s_saved_inside || flags.table_inside) ; 232 flags.table_inside <- false ; 233 let active = !cur_out.active 234 and pending = !cur_out.pending in 235 flags.ncols <- flags.ncols + 1 ; 236 close_flow DFLOW ; 237 close_flow TD ; 238 if !verbose > 2 then begin 239 prerr_endline "Added Item to Display" ; 240 Out.debug stderr !cur_out.out ; 241 end; 242 open_display_cell "" ; 243 open_block DFLOW "" ; 244 !cur_out.pending <- as_envs active pending ; 245 !cur_out.active <- [] ; 246 if is_freeze then push out_stack (Freeze f) 247 end else begin 248 if !verbose > 2 then begin 249 Out.debug stderr !cur_out.out ; 250 prerr_endline "No Item" ; 251 prerr_endline ("flags: empty="^sbool flags.empty^" blank="^sbool flags.blank) 252 end 253 end 254 255let item_display () = do_item_display false 256and force_item_display () = do_item_display true 257 258 259let erase_display () = 260 erase_block DFLOW ; 261 erase_block TD ; 262 erase_block (DISPLAY false); 263 try_close_display () 264 265 266let open_maths display = 267 push stacks.s_in_math flags.in_math; 268 flags.in_math <- true; 269 open_group ""; 270 if display then open_display true 271 272let close_maths display = 273 (* force a table in that case, because we want to apply style class *) 274 if display then close_display true ; 275 close_group () ; 276 flags.in_math <- pop stacks.s_in_math 277 278(* vertical display *) 279 280let open_vdisplay center display = 281 if !verbose > 1 then 282 prerr_endline "open_vdisplay"; 283 if not display then raise (Misc.Fatal ("VDISPLAY in non-display mode")); 284 open_block TABLE (display_arg center !verbose) 285 286and close_vdisplay () = 287 if !verbose > 1 then 288 prerr_endline "close_vdisplay"; 289 close_block TABLE 290 291and open_vdisplay_row trarg tdarg = 292 if !verbose > 1 then 293 prerr_endline "open_vdisplay_row"; 294 open_block TR trarg ; 295 open_display_cell tdarg ; 296 open_display false 297 298and close_vdisplay_row () = 299 if !verbose > 1 then 300 prerr_endline "close_vdisplay_row"; 301 close_display false ; 302 force_block TD " " ; 303 close_block TR 304 305 306 307(* Sup/Sub stuff *) 308 309let put_sup_sub display scanner (arg : string Lexstate.arg) = 310 if display then open_display false else open_block INTERN "" ; 311 scanner arg ; 312 if display then close_display false else close_block INTERN 313 314let reput_sup_sub tag = function 315 | "" -> () 316 | s -> 317 open_block INTERN "" ; 318 clearstyle () ; 319 if not (flags.in_pre && !pedantic) then begin 320 put_char '<' ; 321 put tag ; 322 put_char '>' 323 end ; 324 put s ; 325 if not (flags.in_pre && !pedantic) then begin 326 put "</" ; 327 put tag ; 328 put_char '>' 329 end ; 330 close_block INTERN 331 332 333let standard_sup_sub scanner what sup sub display = 334 let sup,fsup = 335 hidden_to_string (fun () -> put_sup_sub display scanner sup) 336 in 337 let sub,fsub = 338 hidden_to_string (fun () -> put_sup_sub display scanner sub) in 339 340 if display && (fsub.table_inside || fsup.table_inside) then begin 341 force_item_display () ; 342 open_vdisplay false display ; 343 if sup <> "" then begin 344 open_vdisplay_row "" "" ; 345 clearstyle () ; 346 put sup ; 347 close_vdisplay_row () 348 end ; 349 open_vdisplay_row "" "" ; 350 what (); 351 close_vdisplay_row () ; 352 if sub <> "" then begin 353 open_vdisplay_row "" "" ; 354 clearstyle () ; 355 put sub ; 356 close_vdisplay_row () 357 end ; 358 close_vdisplay () ; 359 force_item_display () 360 end else begin 361 what (); 362 reput_sup_sub "sub" sub ; 363 reput_sup_sub "sup" sup 364 end 365 366 367let limit_sup_sub scanner what sup sub display = 368 let sup = to_string (fun () -> put_sup_sub display scanner sup) 369 and sub = to_string (fun () -> put_sup_sub display scanner sub) in 370 if sup = "" && sub = "" then 371 what () 372 else begin 373 force_item_display () ; 374 open_vdisplay false display ; 375 open_vdisplay_row "" "style=\"text-align:center\"" ; 376 put sup ; 377 close_vdisplay_row () ; 378 open_vdisplay_row "" "style=\"text-align:center\"" ; 379 what () ; 380 close_vdisplay_row () ; 381 open_vdisplay_row "" "style=\"text-align:center\"" ; 382 put sub ; 383 close_vdisplay_row () ; 384 close_vdisplay () ; 385 force_item_display () 386 end 387 388let int_sup_sub something vsize scanner what sup sub display = 389 let sup = to_string (fun () -> put_sup_sub display scanner sup) 390 and sub = to_string (fun () -> put_sup_sub display scanner sub) in 391 if something then begin 392 force_item_display () ; 393 what () ; 394 force_item_display () 395 end ; 396 if sup <> "" || sub <> "" then begin 397 open_vdisplay false display ; 398 open_vdisplay_row "" "style=\"text-align:left\"" ; 399 put sup ; 400 close_vdisplay_row () ; 401 open_vdisplay_row "" "style=\"text-align:left\"" ; 402 for _i = 2 to vsize do 403 skip_line () 404 done ; 405 close_vdisplay_row () ; 406 open_vdisplay_row "" "style=\"text-align:left\"" ; 407 put sub ; 408 close_vdisplay_row () ; 409 close_vdisplay () ; 410 force_item_display () 411 end 412 413 414let insert_vdisplay open_fun = 415 if !verbose > 2 then begin 416 prerr_flags "=> insert_vdisplay" ; 417 end ; 418 try 419 let mods = to_pending !cur_out.pending !cur_out.active in 420 let bs,bargs,bout = pop_out out_stack in 421 if bs <> DFLOW then 422 failclose "insert_vdisplay" bs DFLOW ; 423 let ps,pargs,pout = pop_out out_stack in 424 if ps <> TD then 425 failclose "insert_vdisplay" ps TD ; 426 let pps,ppargs,ppout = pop_out out_stack in 427 let center = 428 match pps with 429 | DISPLAY b -> b 430 | _ -> failclose "insert_vdisplay" pps (DISPLAY false) in 431 let new_out = create_status_from_scratch false [] in 432 push_out out_stack (DISPLAY false,ppargs,new_out) ; 433 push_out out_stack (ps,pargs,pout) ; 434 push_out out_stack (bs,bargs,bout) ; 435 close_display false ; 436 cur_out := ppout ; 437 let () = open_fun center in (* force bool -> unit' type *) 438 do_put (Out.to_string new_out.out) ; 439 flags.empty <- false ; flags.blank <- false ; 440 if !verbose > 2 then begin 441 prerr_string "insert_vdisplay -> " ; 442 pretty_mods stderr mods ; 443 prerr_newline () 444 end ; 445 if !verbose > 2 then 446 prerr_flags "<= insert_vdisplay" ; 447 mods 448 with PopFreeze -> 449 raise (UserError "\\over should be properly parenthesized") 450 451 452let line_in_vdisplay_row () = 453 open_block TR "" ; 454 open_block TD "class=\"hbar\"" ; 455 (* 456 close_mods () ; 457 line_in_table () ; 458 *) 459 force_block TD "" ; 460 force_block TR "" 461 462let over _lexbuf = 463 let mods = insert_vdisplay 464 (fun center -> 465 open_vdisplay center true ; 466 open_vdisplay_row "" "style=\"text-align:center\"") in 467 close_vdisplay_row () ; 468 line_in_vdisplay_row () ; 469 open_vdisplay_row "" "style=\"text-align:center\"" ; 470 close_mods () ; 471 open_mods mods ; 472 freeze 473 (fun () -> 474 close_vdisplay_row () ; 475 close_vdisplay ()) 476 477(* Gestion of left and right delimiters *) 478 479let left _ k_delim k = 480 let _,f,is_freeze = end_item_display () in 481 delay 482 (fun vsize -> 483 begin_item_display (fun () -> ()) false ; 484 k_delim vsize ; 485 ignore (end_item_display ()) ; 486 begin_item_display (fun () -> ()) false ; 487 k vsize ; 488 let _ = end_item_display () in 489 ()) ; 490 begin_item_display f is_freeze 491 492let right _ k_delim = 493 let vsize,f,is_freeze = end_item_display () in 494 begin_item_display (fun () -> ()) false ; 495 k_delim vsize; 496 ignore (end_item_display ()) ; 497 flush vsize ; 498 begin_item_display f is_freeze ; 499 vsize 500