BBox.ts 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  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 a bounding-box object and operations on it
  19. *
  20. * @author dpvc@mathjax.org (Davide Cervone)
  21. */
  22. import {BIGDIMEN} from './lengths.js';
  23. /**
  24. * The data used to initialize a BBox
  25. */
  26. export type BBoxData = {
  27. w?: number,
  28. h?: number,
  29. d?: number
  30. };
  31. /*****************************************************************/
  32. /**
  33. * The BBox class
  34. */
  35. export class BBox {
  36. /**
  37. * Constant for pwidth of full width box
  38. */
  39. public static fullWidth = '100%';
  40. /**
  41. * CSS styles that affect BBoxes
  42. */
  43. public static StyleAdjust: [string, string, number?][] = [
  44. ['borderTopWidth', 'h'],
  45. ['borderRightWidth', 'w'],
  46. ['borderBottomWidth', 'd'],
  47. ['borderLeftWidth', 'w', 0],
  48. ['paddingTop', 'h'],
  49. ['paddingRight', 'w'],
  50. ['paddingBottom', 'd'],
  51. ['paddingLeft', 'w', 0]
  52. ];
  53. /**
  54. * These are the data stored for a bounding box
  55. */
  56. /* tslint:disable:jsdoc-require */
  57. public w: number;
  58. public h: number;
  59. public d: number;
  60. public scale: number;
  61. public rscale: number; // scale relative to the parent's scale
  62. public L: number; // extra space on the left
  63. public R: number; // extra space on the right
  64. public pwidth: string; // percentage width (for tables)
  65. public ic: number; // italic correction
  66. public sk: number; // skew
  67. public dx: number; // offset for combining characters as accents
  68. /* tslint:enable */
  69. /**
  70. * @return {BBox} A BBox initialized to zeros
  71. */
  72. public static zero(): BBox {
  73. return new BBox({h: 0, d: 0, w: 0});
  74. }
  75. /**
  76. * @return {BBox} A BBox with height and depth not set
  77. */
  78. public static empty(): BBox {
  79. return new BBox();
  80. }
  81. /**
  82. * @param {BBoxData} def The data with which to initialize the BBox
  83. *
  84. * @constructor
  85. */
  86. constructor(def: BBoxData = {w: 0, h: -BIGDIMEN, d: -BIGDIMEN}) {
  87. this.w = def.w || 0;
  88. this.h = ('h' in def ? def.h : -BIGDIMEN);
  89. this.d = ('d' in def ? def.d : -BIGDIMEN);
  90. this.L = this.R = this.ic = this.sk = this.dx = 0;
  91. this.scale = this.rscale = 1;
  92. this.pwidth = '';
  93. }
  94. /**
  95. * Set up a bbox for append() and combine() operations
  96. * @return {BBox} the boox itself (for chaining calls)
  97. */
  98. public empty(): BBox {
  99. this.w = 0;
  100. this.h = this.d = -BIGDIMEN;
  101. return this;
  102. }
  103. /**
  104. * Convert any unspecified values into zeros
  105. */
  106. public clean () {
  107. if (this.w === -BIGDIMEN) this.w = 0;
  108. if (this.h === -BIGDIMEN) this.h = 0;
  109. if (this.d === -BIGDIMEN) this.d = 0;
  110. }
  111. /**
  112. * @param {number} scale The scale to use to modify the bounding box size
  113. */
  114. public rescale(scale: number) {
  115. this.w *= scale;
  116. this.h *= scale;
  117. this.d *= scale;
  118. }
  119. /**
  120. * @param {BBox} cbox A bounding to combine with this one
  121. * @param {number} x An x-offest for the child bounding box
  122. * @param {number} y A y-offset for the child bounding box
  123. */
  124. public combine(cbox: BBox, x: number = 0, y: number = 0) {
  125. let rscale = cbox.rscale;
  126. let w = x + rscale * (cbox.w + cbox.L + cbox.R);
  127. let h = y + rscale * cbox.h;
  128. let d = rscale * cbox.d - y;
  129. if (w > this.w) this.w = w;
  130. if (h > this.h) this.h = h;
  131. if (d > this.d) this.d = d;
  132. }
  133. /**
  134. * @param {BBox} cbox A bounding box to be added to the right of this one
  135. */
  136. public append(cbox: BBox) {
  137. let scale = cbox.rscale;
  138. this.w += scale * (cbox.w + cbox.L + cbox.R);
  139. if (scale * cbox.h > this.h) {
  140. this.h = scale * cbox.h;
  141. }
  142. if (scale * cbox.d > this.d) {
  143. this.d = scale * cbox.d;
  144. }
  145. }
  146. /**
  147. * @param {BBox} cbox The bounding box to use to overwrite this one
  148. */
  149. public updateFrom(cbox: BBox) {
  150. this.h = cbox.h;
  151. this.d = cbox.d;
  152. this.w = cbox.w;
  153. if (cbox.pwidth) {
  154. this.pwidth = cbox.pwidth;
  155. }
  156. }
  157. }