mmultiscripts.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296
  1. /* -*- Mode: Javascript; indent-tabs-mode:nil; js-indent-level: 2 -*- */
  2. /* vim: set ts=2 et sw=2 tw=80: */
  3. /*************************************************************
  4. *
  5. * MathJax/jax/output/CommonHTML/autoload/mmultiscripts.js
  6. *
  7. * Implements the CommonHTML output for <mmultiscripts> elements.
  8. *
  9. * ---------------------------------------------------------------------
  10. *
  11. * Copyright (c) 2015-2017 The MathJax Consortium
  12. *
  13. * Licensed under the Apache License, Version 2.0 (the "License");
  14. * you may not use this file except in compliance with the License.
  15. * You may obtain a copy of the License at
  16. *
  17. * http://www.apache.org/licenses/LICENSE-2.0
  18. *
  19. * Unless required by applicable law or agreed to in writing, software
  20. * distributed under the License is distributed on an "AS IS" BASIS,
  21. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  22. * See the License for the specific language governing permissions and
  23. * limitations under the License.
  24. */
  25. MathJax.Hub.Register.StartupHook("CommonHTML Jax Ready",function () {
  26. var VERSION = "2.7.2";
  27. var MML = MathJax.ElementJax.mml,
  28. CHTML = MathJax.OutputJax.CommonHTML;
  29. MML.mmultiscripts.Augment({
  30. toCommonHTML: function (node,options) {
  31. var stretch = (options||{}).stretch;
  32. if (!stretch) {
  33. node = this.CHTMLcreateNode(node);
  34. this.CHTMLhandleStyle(node);
  35. this.CHTMLgetVariant();
  36. this.CHTMLhandleScale(node);
  37. }
  38. CHTML.BBOX.empty(this.CHTML);
  39. //
  40. // Get base node
  41. //
  42. var base, bbox;
  43. if (stretch) {
  44. base = CHTML.getNode(node,"mjx-base");
  45. } else {
  46. this.CHTMLaddChild(node,0,{type:"mjx-base", noBBox:true, forceChild:true});
  47. base = node.firstChild;
  48. }
  49. bbox = this.CHTMLbboxFor(0);
  50. if (bbox.ic) {
  51. bbox.R -= bbox.ic; // remove IC (added by mo and mi)
  52. if (!stretch) base.style.marginRight = CHTML.Em(-bbox.ic);
  53. delta = 1.3*bbox.ic + .05; // make faked IC be closer to expeted results
  54. }
  55. //
  56. // Collect scripts into horizontal boxes and add them into the node
  57. //
  58. var BOX = {}, BBOX = {};
  59. this.CHTMLgetScripts(BOX,BBOX,stretch,node);
  60. var sub = BOX.sub, sup = BOX.sup, presub = BOX.presub, presup = BOX.presup;
  61. var sbox = BBOX.sub, Sbox = BBOX.sup, pbox = BBOX.presub, Pbox = BBOX.presup;
  62. if (!stretch) this.CHTMLaddBoxes(node,base,BOX);
  63. //
  64. // Get the initial values for the variables
  65. //
  66. var values = this.getValues("scriptlevel","scriptsizemultiplier");
  67. var sscale = (this.Get("scriptlevel") < 3 ? values.scriptsizemultiplier : 1);
  68. var ex = CHTML.TEX.x_height, s = CHTML.TEX.scriptspace;
  69. var q = CHTML.TEX.sup_drop * sscale, r = CHTML.TEX.sub_drop * sscale;
  70. var u = bbox.h - q, v = bbox.d + r, delta = 0, p;
  71. var bmml = this.data[this.base];
  72. if (bmml && (bmml.type === "mi" || bmml.type === "mo")) {
  73. if (bmml.data.join("").length === 1 && bbox.rscale === 1 && !bbox.sH &&
  74. !bmml.Get("largeop")) {u = v = 0}
  75. }
  76. values = this.getValues("displaystyle","subscriptshift","superscriptshift","texprimestyle");
  77. values.subscriptshift = (values.subscriptshift === "" ? 0 : this.CHTMLlength2em(values.subscriptshift));
  78. values.superscriptshift = (values.superscriptshift === "" ? 0 : this.CHTMLlength2em(values.superscriptshift));
  79. var dx = (presub ? s+pbox.w : presup ? s+Pbox.w-delta : 0);
  80. this.CHTML.combine(bbox,dx,0); var x = this.CHTML.w;
  81. //
  82. // Place the scripts as needed
  83. //
  84. if (!sup && !presup) {
  85. v = Math.max(v,CHTML.TEX.sub1,values.subscriptshift);
  86. if (sub) v = Math.max(v,sbox.h-(4/5)*ex);
  87. if (presub) v = Math.max(v,pbox.h-(4/5)*ex);
  88. if (sub) this.CHTMLplaceSubOnly(sub,sbox,x,v,s);
  89. if (presub) this.CHTMLplacePresubOnly(presub,pbox,v,s);
  90. } else {
  91. if (!sub && !presub) {
  92. p = CHTML.TEX[(values.displaystyle ? "sup1" : (values.texprimestyle ? "sup3" : "sup2"))];
  93. u = Math.max(u,p,values.superscriptshift);
  94. if (sup) u = Math.max(u,Sbox.d+(1/4)*ex);
  95. if (presup) u = Math.max(u,Pbox.d+(1/4)*ex);
  96. if (sup) this.CHTMLplaceSupOnly(sup,Sbox,x,delta,u,s);
  97. if (presup) this.CHTMLplacePresupOnly(presup,Pbox,delta,u,s);
  98. } else {
  99. v = Math.max(v,CHTML.TEX.sub2);
  100. var t = CHTML.TEX.rule_thickness;
  101. var h = (sbox||pbox).h, d = (Sbox||Pbox).d;
  102. if (presub) h = Math.max(h,pbox.h);
  103. if (presup) d = Math.max(d,Pbox.d);
  104. if ((u - d) - (h - v) < 3*t) {
  105. v = 3*t - u + d + h; q = (4/5)*ex - (u - d);
  106. if (q > 0) {u += q; v -= q}
  107. }
  108. u = Math.max(u,values.superscriptshift);
  109. v = Math.max(v,values.subscriptshift);
  110. if (sup) {
  111. if (sub) {this.CHTMLplaceSubSup(sub,sbox,sup,Sbox,x,delta,u,v,s)}
  112. else {this.CHTMLplaceSupOnly(sup,Sbox,x,delta,u,s)}
  113. } else if (sub) {this.CHTMLplaceSubOnly(sub,sbox,x,v,s)}
  114. if (presup) {
  115. if (presub) {this.CHTMLplacePresubPresup(presub,pbox,presup,Pbox,delta,u,v,s)}
  116. else {this.CHTMLplacePresupOnly(presup,Pbox,delta,u,s)}
  117. } else if (presub) {this.CHTMLplacePresubOnly(presub,pbox,v,s)}
  118. }
  119. }
  120. this.CHTML.clean();
  121. this.CHTMLhandleSpace(node);
  122. this.CHTMLhandleBBox(node);
  123. this.CHTMLhandleColor(node);
  124. return node;
  125. },
  126. //
  127. // Get the subscript, superscript, presubscript, and presuperscript
  128. // boxes, with proper spacing, and computer their bounding boxes.
  129. //
  130. CHTMLgetScripts: function (BOX,BBOX,stretch,node) {
  131. if (stretch) {
  132. BOX.sub = CHTML.getNode(node,"mjx-sub");
  133. BOX.sup = CHTML.getNode(node,"mjx-sup");
  134. BOX.presub = CHTML.getNode(node,"mjx-presub");
  135. BOX.presup = CHTML.getNode(node,"mjx-presup");
  136. BBOX.sub = this.CHTMLbbox.sub;
  137. BBOX.sup = this.CHTMLbbox.sup;
  138. BBOX.presub = this.CHTMLbbox.presub;
  139. BBOX.presup = this.CHTMLbbox.presup;
  140. return;
  141. }
  142. this.CHTMLbbox = BBOX; // save for when stretched
  143. var state = {i:1, w:0, BOX:BOX, BBOX:BBOX}, m = this.data.length;
  144. var sub = "sub", sup = "sup";
  145. while (state.i < m) {
  146. if ((this.data[state.i]||{}).type === "mprescripts") {
  147. state.i++; state.w = 0;
  148. sub = "presub"; sup = "presup";
  149. } else {
  150. var sbox = this.CHTMLaddScript(sub,state,node);
  151. var Sbox = this.CHTMLaddScript(sup,state,node);
  152. var w = Math.max((sbox ? sbox.rscale*sbox.w : 0),(Sbox ? Sbox.rscale*Sbox.w : 0));
  153. this.CHTMLpadScript(sub,w,sbox,state);
  154. this.CHTMLpadScript(sup,w,Sbox,state);
  155. state.w += w;
  156. }
  157. }
  158. if (BBOX.sub) BBOX.sub.clean();
  159. if (BBOX.sup) BBOX.sup.clean();
  160. if (BBOX.presub) BBOX.presub.clean();
  161. if (BBOX.presup) BBOX.presup.clean();
  162. },
  163. //
  164. // Add a script to the proper box, creating the box if needed,
  165. // and padding the box to account for any <none/> elements.
  166. // Return the bounding box for the script for later use.
  167. //
  168. CHTMLaddScript: function (type,state,node) {
  169. var BOX, BBOX, data = this.data[state.i];
  170. if (data && data.type !== "none" && data.type !== "mprescripts") {
  171. BOX = state.BOX[type];
  172. if (!BOX) {
  173. //
  174. // Add the box to the node temporarily so that it is in the DOM
  175. // (so that CHTMLnodeElement() can be used in the toCommonHTML() below).
  176. // See issue #1480.
  177. //
  178. BOX = state.BOX[type] = CHTML.addElement(node,"mjx-"+type);
  179. BBOX = state.BBOX[type] = CHTML.BBOX.empty();
  180. if (state.w) {
  181. BOX.style.paddingLeft = CHTML.Em(state.w);
  182. BBOX.w = BBOX.r = state.w; BBOX.x = state.w;
  183. }
  184. }
  185. data.toCommonHTML(BOX);
  186. BBOX = data.CHTML;
  187. }
  188. if (data && data.type !== "mprescripts") state.i++;
  189. return BBOX;
  190. },
  191. //
  192. // Add padding to the script box to make match the width of the
  193. // super- or subscript that is above or below it, and adjust the
  194. // bounding box for the script row. If these are pre-scripts,
  195. // right-justify the scripts, otherwise, left-justify them.
  196. //
  197. CHTMLpadScript: function (type,w,bbox,state) {
  198. if (!bbox) bbox = {w:0, fake:1, rscale:1};
  199. var BBOX = state.BBOX[type], dx = 0, dw = 0;
  200. if (BBOX) {
  201. if (bbox.rscale*bbox.w < w) {
  202. var BOX = state.BOX[type]; dw = w-bbox.rscale*bbox.w;
  203. var space = CHTML.Element("mjx-spacer",{style:{width:CHTML.Em(dw)}});
  204. if (type.substr(0,3) === "pre" && !bbox.fake) {
  205. BOX.insertBefore(space,BOX.lastChild);
  206. dx = dw; dw = 0;
  207. } else {
  208. BOX.appendChild(space);
  209. }
  210. }
  211. if (bbox.fake) {BBOX.w += dx} else {BBOX.combine(bbox,BBOX.w+dx,0)}
  212. BBOX.w += dw;
  213. }
  214. },
  215. //
  216. // Add the boxes into the main node, creating stacks when needed
  217. //
  218. CHTMLaddBoxes: function (node,base,BOX) {
  219. var sub = BOX.sub, sup = BOX.sup, presub = BOX.presub, presup = BOX.presup;
  220. if (presub && presup) {
  221. var prestack = CHTML.Element("mjx-prestack"); node.insertBefore(prestack,base);
  222. prestack.appendChild(presup); prestack.appendChild(presub);
  223. } else {
  224. if (presub) node.insertBefore(presub,base);
  225. if (presup) node.insertBefore(presup,base);
  226. }
  227. if (sub && sup) {
  228. var stack = CHTML.addElement(node,"mjx-stack");
  229. stack.appendChild(sup); stack.appendChild(sub);
  230. } else {
  231. if (sub) node.appendChild(sub);
  232. if (sup) node.appendChild(sup);
  233. }
  234. },
  235. //
  236. // Handle positioning the various scripts
  237. //
  238. CHTMLplaceSubOnly: function (sub,sbox,x,v,s) {
  239. sub.style.verticalAlign = CHTML.Em(-v);
  240. sub.style.marginRight = CHTML.Em(s); sbox.w += s;
  241. this.CHTML.combine(sbox,x,-v);
  242. },
  243. CHTMLplaceSupOnly: function (sup,Sbox,x,delta,u,s) {
  244. sup.style.verticalAlign = CHTML.Em(u);
  245. sup.style.paddingLeft = CHTML.Em(delta);
  246. sup.style.paddingRight = CHTML.Em(s); Sbox.w += s;
  247. this.CHTML.combine(Sbox,x+delta,u);
  248. },
  249. CHTMLplaceSubSup: function (sub,sbox,sup,Sbox,x,delta,u,v,s) {
  250. sub.style.paddingRight = CHTML.Em(s); sbox.w += s;
  251. sup.style.paddingBottom = CHTML.Em(u+v-Sbox.d-sbox.h);
  252. sup.style.paddingLeft = CHTML.Em(delta+(Sbox.x||0));
  253. sup.style.paddingRight = CHTML.Em(s); Sbox.w += s;
  254. sup.parentNode.style.verticalAlign = CHTML.Em(-v);
  255. this.CHTML.combine(sbox,x,-v);
  256. this.CHTML.combine(Sbox,x+delta,u);
  257. },
  258. CHTMLplacePresubOnly: function (presub,pbox,v,s) {
  259. presub.style.verticalAlign = CHTML.Em(-v);
  260. presub.style.marginLeft = CHTML.Em(s);
  261. this.CHTML.combine(pbox,s,-v);
  262. },
  263. CHTMLplacePresupOnly: function (presup,Pbox,delta,u,s) {
  264. presup.style.verticalAlign = CHTML.Em(u);
  265. presup.style.paddingLeft = CHTML.Em(s);
  266. presup.style.paddingRight = CHTML.Em(-delta);
  267. this.CHTML.combine(Pbox,s,u);
  268. },
  269. CHTMLplacePresubPresup: function (presub,pbox,presup,Pbox,delta,u,v,s) {
  270. presub.style.paddingLeft = CHTML.Em(s);
  271. presup.style.paddingBottom = CHTML.Em(u+v-Pbox.d-pbox.h);
  272. presup.style.paddingLeft = CHTML.Em(delta+s+(Pbox.x||0));
  273. presup.style.paddingRight = CHTML.Em(-delta);
  274. presup.parentNode.style.verticalAlign = CHTML.Em(-v);
  275. this.CHTML.combine(pbox,s,-v);
  276. this.CHTML.combine(Pbox,s+delta,u);
  277. },
  278. //
  279. // Handle stretchy bases
  280. //
  281. CHTMLstretchH: MML.mbase.CHTMLstretchH,
  282. CHTMLstretchV: MML.mbase.CHTMLstretchV
  283. });
  284. MathJax.Hub.Startup.signal.Post("CommonHTML mmultiscripts Ready");
  285. MathJax.Ajax.loadComplete(CHTML.autoloadDir+"/mmultiscripts.js");
  286. });