msubsup.ts 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  1. /*************************************************************
  2. *
  3. * Copyright (c) 2017-2022 The MathJax Consortium
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License");
  6. * you may not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. */
  17. /**
  18. * @fileoverview Implements the CommonMsubsup wrapper mixin for the MmlMsubsup object
  19. * and the special cases CommonMsub and CommonMsup
  20. *
  21. * @author dpvc@mathjax.org (Davide Cervone)
  22. */
  23. import {AnyWrapper, Constructor} from '../Wrapper.js';
  24. import {CommonScriptbase, ScriptbaseConstructor} from './scriptbase.js';
  25. import {BBox} from '../../../util/BBox.js';
  26. import {MmlMsubsup, MmlMsub, MmlMsup} from '../../../core/MmlTree/MmlNodes/msubsup.js';
  27. /*****************************************************************/
  28. /**
  29. * The CommonMsub interface
  30. *
  31. * @template W The child-node Wrapper class
  32. */
  33. export interface CommonMsub<W extends AnyWrapper> extends CommonScriptbase<W> {
  34. }
  35. /**
  36. * Shorthand for the CommonMsub constructor
  37. *
  38. * @template W The child-node Wrapper class
  39. */
  40. export type MsubConstructor<W extends AnyWrapper> = Constructor<CommonMsub<W>>;
  41. /*****************************************************************/
  42. /**
  43. * The CommonMsub wrapper mixin for the MmlMsub object
  44. *
  45. * @template W The child-node Wrapper class
  46. * @template T The Wrapper class constructor type
  47. */
  48. export function CommonMsubMixin<
  49. W extends AnyWrapper,
  50. T extends ScriptbaseConstructor<W>
  51. >(Base: T): MsubConstructor<W> & T {
  52. return class extends Base {
  53. /**
  54. * Do not include italic correction
  55. */
  56. public static useIC: boolean = false;
  57. /**
  58. * @override
  59. */
  60. public get scriptChild() {
  61. return this.childNodes[(this.node as MmlMsub).sub];
  62. }
  63. /**
  64. * Get the shift for the subscript
  65. *
  66. * @override
  67. */
  68. public getOffset() {
  69. return [0, -this.getV()];
  70. }
  71. };
  72. }
  73. /*****************************************************************/
  74. /**
  75. * The CommonMsup interface
  76. *
  77. * @template W The child-node Wrapper class
  78. */
  79. export interface CommonMsup<W extends AnyWrapper> extends CommonScriptbase<W> {
  80. }
  81. /**
  82. * Shorthand for the CommonMsup constructor
  83. *
  84. * @template W The child-node Wrapper class
  85. */
  86. export type MsupConstructor<W extends AnyWrapper> = Constructor<CommonMsup<W>>;
  87. /*****************************************************************/
  88. /**
  89. * The CommonMsup wrapper mixin for the MmlMsup object
  90. *
  91. * @template W The child-node Wrapper class
  92. * @template T The Wrapper class constructor type
  93. */
  94. export function CommonMsupMixin<
  95. W extends AnyWrapper,
  96. T extends ScriptbaseConstructor<W>
  97. >(Base: T): MsupConstructor<W> & T {
  98. return class extends Base {
  99. /**
  100. * @override
  101. */
  102. public get scriptChild() {
  103. return this.childNodes[(this.node as MmlMsup).sup];
  104. }
  105. /**
  106. * Get the shift for the superscript
  107. *
  108. * @override
  109. */
  110. public getOffset() {
  111. const x = this.getAdjustedIc() - (this.baseRemoveIc ? 0 : this.baseIc);
  112. return [x, this.getU()];
  113. }
  114. };
  115. }
  116. /*****************************************************************/
  117. /**
  118. * The CommonMsubsup interface
  119. *
  120. * @template W The child-node Wrapper class
  121. */
  122. export interface CommonMsubsup<W extends AnyWrapper> extends CommonScriptbase<W> {
  123. /**
  124. * Cached values for the script offsets and separation (so if they are
  125. * computed in computeBBox(), they don't have to be recomputed during output)
  126. */
  127. UVQ: number[];
  128. /**
  129. * The wrapper for the subscript
  130. */
  131. readonly subChild: W;
  132. /**
  133. * The wrapper for the superscript
  134. */
  135. readonly supChild: W;
  136. /**
  137. * Get the shift for the scripts and their separation (TeXBook Appendix G 18adef)
  138. *
  139. * @param {BBox} subbox The bounding box of the superscript
  140. * @param {BBox} supbox The bounding box of the subscript
  141. * @return {number[]} The vertical offsets for super and subscripts, and the space between them
  142. */
  143. getUVQ(subbox?: BBox, supbox?: BBox): number[];
  144. }
  145. /**
  146. * Shorthand for the CommonMsubsup constructor
  147. *
  148. * @template W The child-node Wrapper class
  149. */
  150. export type MsubsupConstructor<W extends AnyWrapper> = Constructor<CommonMsubsup<W>>;
  151. /*****************************************************************/
  152. /**
  153. * The CommomMsubsup wrapper for the MmlMsubsup object
  154. *
  155. * @template W The child-node Wrapper class
  156. * @template T The Wrapper class constructor type
  157. */
  158. export function CommonMsubsupMixin<
  159. W extends AnyWrapper,
  160. T extends ScriptbaseConstructor<W>
  161. >(Base: T): MsubsupConstructor<W> & T {
  162. return class extends Base {
  163. /**
  164. * Do not include italic correction
  165. */
  166. public static useIC: boolean = false;
  167. /**
  168. * Cached values for the script offsets and separation (so if they are
  169. * computed in computeBBox(), they don't have to be recomputed during output)
  170. */
  171. public UVQ: number[] = null;
  172. /**
  173. * @return {W} The wrapper for the subscript
  174. */
  175. public get subChild(): W {
  176. return this.childNodes[(this.node as MmlMsubsup).sub];
  177. }
  178. /**
  179. * @return {W} The wrapper for the superscript
  180. */
  181. public get supChild(): W {
  182. return this.childNodes[(this.node as MmlMsubsup).sup];
  183. }
  184. /**
  185. * @override
  186. */
  187. public computeBBox(bbox: BBox, recompute: boolean = false) {
  188. const basebox = this.baseChild.getOuterBBox();
  189. const [subbox, supbox] = [this.subChild.getOuterBBox(), this.supChild.getOuterBBox()];
  190. bbox.empty();
  191. bbox.append(basebox);
  192. const w = this.getBaseWidth();
  193. const x = this.getAdjustedIc();
  194. const [u, v] = this.getUVQ();
  195. bbox.combine(subbox, w, v);
  196. bbox.combine(supbox, w + x, u);
  197. bbox.w += this.font.params.scriptspace;
  198. bbox.clean();
  199. this.setChildPWidths(recompute);
  200. }
  201. /**
  202. * Get the shift for the scripts and their separation (TeXBook Appendix G 18adef)
  203. *
  204. * @param {BBox} subbox The bounding box of the superscript
  205. * @param {BBox} supbox The bounding box of the subscript
  206. * @return {number[]} The vertical offsets for super and subscripts, and the space between them
  207. */
  208. public getUVQ(
  209. subbox: BBox = this.subChild.getOuterBBox(),
  210. supbox: BBox = this.supChild.getOuterBBox()
  211. ): number[] {
  212. const basebox = this.baseCore.getOuterBBox();
  213. if (this.UVQ) return this.UVQ;
  214. const tex = this.font.params;
  215. const t = 3 * tex.rule_thickness;
  216. const subscriptshift = this.length2em(this.node.attributes.get('subscriptshift'), tex.sub2);
  217. const drop = this.baseCharZero(basebox.d * this.baseScale + tex.sub_drop * subbox.rscale);
  218. //
  219. // u and v are the veritcal shifts of the scripts, initially set to minimum values and then adjusted
  220. //
  221. let [u, v] = [this.getU(), Math.max(drop, subscriptshift)];
  222. //
  223. // q is the space currently between the super- and subscripts.
  224. // If it is less than 3 rule thicknesses,
  225. // increase the subscript offset to make the space 3 rule thicknesses
  226. // If the bottom of the superscript is below 4/5 of the x-height
  227. // raise both the super- and subscripts by the difference
  228. // (make the bottom of the superscript be at 4/5 the x-height, and the
  229. // subscript 3 rule thickness below that).
  230. //
  231. let q = (u - supbox.d * supbox.rscale) - (subbox.h * subbox.rscale - v);
  232. if (q < t) {
  233. v += t - q;
  234. const p = (4 / 5) * tex.x_height - (u - supbox.d * supbox.rscale);
  235. if (p > 0) {
  236. u += p;
  237. v -= p;
  238. }
  239. }
  240. //
  241. // Make sure the shifts are at least the minimum amounts and
  242. // return the shifts and the space between the scripts
  243. //
  244. u = Math.max(this.length2em(this.node.attributes.get('superscriptshift'), u), u);
  245. v = Math.max(this.length2em(this.node.attributes.get('subscriptshift'), v), v);
  246. q = (u - supbox.d * supbox.rscale) - (subbox.h * subbox.rscale - v);
  247. this.UVQ = [u, -v, q];
  248. return this.UVQ;
  249. }
  250. };
  251. }