2222 */
2323
2424import { CHTMLWrapper } from '../Wrapper.js' ;
25+ import { CHTMLWrapperFactory } from '../WrapperFactory.js' ;
26+ import { CHTMLmo } from './mo.js' ;
2527import { MmlMfrac } from '../../../core/MmlTree/MmlNodes/mfrac.js' ;
2628import { MmlNode } from '../../../core/MmlTree/MmlNode.js' ;
2729import { BBox } from '../BBox.js' ;
@@ -122,32 +124,75 @@ export class CHTMLmfrac<N, T, D> extends CHTMLWrapper<N, T, D> {
122124
123125 } ;
124126
127+ protected bevel : CHTMLmo < N , T , D > = null ;
128+
129+ /************************************************/
130+
131+ /*
132+ * @override
133+ * @constructor
134+ */
135+ constructor ( factory : CHTMLWrapperFactory < N , T , D > , node : MmlNode , parent : CHTMLWrapper < N , T , D > = null ) {
136+ super ( factory , node , parent ) ;
137+ //
138+ // create internal bevel mo element
139+ //
140+ if ( this . node . attributes . get ( 'bevelled' ) ) {
141+ const { H} = this . getBevelData ( this . isDisplay ( ) ) ;
142+ const bevel = this . bevel = this . createMo ( '/' ) ;
143+ bevel . canStretch ( DIRECTION . Vertical ) ;
144+ bevel . getStretchedVariant ( [ H ] , true ) ;
145+ }
146+ }
147+
125148 /*
126149 * @override
127150 */
128151 public toCHTML ( parent : N ) {
129152 this . standardCHTMLnode ( parent ) ;
130153 const { linethickness, bevelled} = this . node . attributes . getList ( 'linethickness' , 'bevelled' ) ;
154+ const display = this . isDisplay ( ) ;
155+ if ( bevelled ) {
156+ this . makeBevelled ( display ) ;
157+ } else {
158+ const thickness = this . length2em ( String ( linethickness ) ) ;
159+ if ( thickness === 0 ) {
160+ this . makeAtop ( display ) ;
161+ } else {
162+ this . makeFraction ( display , thickness ) ;
163+ }
164+ }
165+ }
166+
167+ /*
168+ * @override
169+ */
170+ public computeBBox ( bbox : BBox ) {
171+ bbox . empty ( ) ;
172+ const { linethickness, bevelled} = this . node . attributes . getList ( 'linethickness' , 'bevelled' ) ;
173+ const display = this . isDisplay ( ) ;
131174 if ( bevelled ) {
132- this . makeBevelled ( ) ;
175+ this . getBevelledBBox ( bbox , display ) ;
133176 } else {
134177 const thickness = this . length2em ( String ( linethickness ) ) ;
135178 if ( thickness === 0 ) {
136- this . makeAtop ( ) ;
179+ this . getAtopBBox ( bbox , display ) ;
137180 } else {
138- this . makeFraction ( thickness ) ;
181+ this . getFractionBBox ( bbox , display , thickness ) ;
139182 }
140183 }
184+ bbox . clean ( ) ;
141185 }
142186
187+ /************************************************/
188+
143189 /*
144- * @param {number } t The rule line thickness
190+ * @param {boolean } display True when fraction is in display mode
191+ * @param {number } t The rule line thickness
145192 */
146- protected makeFraction ( t : number ) {
147- const { displaystyle, scriptlevel, numalign, denomalign} =
148- this . node . attributes . getList ( 'displaystyle' , 'scriptlevel' , 'numalign' , 'denomalign' ) ;
193+ protected makeFraction ( display : boolean , t : number ) {
194+ const { numalign, denomalign} = this . node . attributes . getList ( 'numalign' , 'denomalign' ) ;
149195 const withDelims = this . node . getProperty ( 'texWithDelims' ) ;
150- const display = ( displaystyle && scriptlevel === 0 ) ;
151196 //
152197 // Attributes to set for the different elements making up the fraction
153198 //
@@ -189,11 +234,31 @@ export class CHTMLmfrac<N, T, D> extends CHTMLWrapper<N, T, D> {
189234 this . childNodes [ 1 ] . toCHTML ( den ) ;
190235 }
191236
192- protected makeAtop ( ) {
193- const { displaystyle, scriptlevel, numalign, denomalign} =
194- this . node . attributes . getList ( 'displaystyle' , 'scriptlevel' , 'numalign' , 'denomalign' ) ;
237+ /*
238+ * @param {BBox } bbox The buonding box to modify
239+ * @param {boolean } display True for display-mode fractions
240+ * @param {number } t The thickness of the line
241+ */
242+ protected getFractionBBox ( bbox : BBox , display : boolean , t : number ) {
243+ const nbox = this . childNodes [ 0 ] . getBBox ( ) ;
244+ const dbox = this . childNodes [ 1 ] . getBBox ( ) ;
245+ const fparam = this . font . params ;
246+ const pad = ( this . node . getProperty ( 'texWithDelims' ) as boolean ? 0 : fparam . nulldelimiterspace ) ;
247+ const a = fparam . axis_height ;
248+ const T = ( display ? 3.5 : 1.5 ) * t ;
249+ bbox . combine ( nbox , 0 , a + T + Math . max ( nbox . d * nbox . rscale , ( display ? fparam . num1 : fparam . num2 ) - a - T ) ) ;
250+ bbox . combine ( dbox , 0 , a - T - Math . max ( dbox . h * dbox . rscale , ( display ? fparam . denom1 : fparam . denom2 ) + a - T ) ) ;
251+ bbox . w += 2 * pad + .2 ;
252+ }
253+
254+ /************************************************/
255+
256+ /*
257+ * @param {boolean } display True when fraction is in display mode
258+ */
259+ protected makeAtop ( display : boolean ) {
260+ const { numalign, denomalign} = this . node . attributes . getList ( 'numalign' , 'denomalign' ) ;
195261 const withDelims = this . node . getProperty ( 'texWithDelims' ) ;
196- const display = ( displaystyle && scriptlevel === 0 ) ;
197262 //
198263 // Attributes to set for the different elements making up the fraction
199264 //
@@ -217,7 +282,19 @@ export class CHTMLmfrac<N, T, D> extends CHTMLWrapper<N, T, D> {
217282 ] ) ) ;
218283 this . childNodes [ 0 ] . toCHTML ( num ) ;
219284 this . childNodes [ 1 ] . toCHTML ( den ) ;
220- this . drawBBox ( ) ;
285+ }
286+
287+ /*
288+ * @param {BBox } bbox The bounding box to modify
289+ * @param {boolean } display True for display-mode fractions
290+ */
291+ protected getAtopBBox ( bbox : BBox , display : boolean ) {
292+ const fparam = this . font . params ;
293+ const pad = ( this . node . getProperty ( 'texWithDelims' ) as boolean ? 0 : fparam . nulldelimiterspace ) ;
294+ const { u, v, nbox, dbox} = this . getUVQ ( display ) ;
295+ bbox . combine ( nbox , 0 , u ) ;
296+ bbox . combine ( dbox , 0 , - v ) ;
297+ bbox . w += 2 * pad ;
221298 }
222299
223300 /*
@@ -249,61 +326,80 @@ export class CHTMLmfrac<N, T, D> extends CHTMLWrapper<N, T, D> {
249326 return { u, v, q, nbox, dbox} ;
250327 }
251328
252- protected makeBevelled ( ) {
253- }
254-
329+ /************************************************/
255330
256331 /*
257- * @override
332+ * @param { boolean } display True when fraction is in display mode
258333 */
259- public computeBBox ( bbox : BBox ) {
260- bbox . empty ( ) ;
261- const { linethickness, bevelled} = this . node . attributes . getList ( 'linethickness' , 'bevelled' ) ;
262- if ( bevelled ) {
263- this . getBevelledBBox ( bbox ) ;
264- } else {
265- const thickness = this . length2em ( String ( linethickness ) ) ;
266- if ( thickness === 0 ) {
267- this . getAtopBBox ( bbox ) ;
268- } else {
269- this . getFractionBBox ( bbox , thickness ) ;
270- }
334+ protected makeBevelled ( display : boolean ) {
335+ const adaptor = this . adaptor ;
336+ //
337+ // Create HTML tree
338+ //
339+ this . childNodes [ 0 ] . toCHTML ( this . chtml ) ;
340+ this . bevel . toCHTML ( this . chtml ) ;
341+ this . childNodes [ 1 ] . toCHTML ( this . chtml ) ;
342+ //
343+ // Place the parts
344+ //
345+ const { u, v, delta, nbox, dbox} = this . getBevelData ( display ) ;
346+ if ( u ) {
347+ const num = this . childNodes [ 0 ] . chtml ;
348+ adaptor . setStyle ( num , 'verticalAlign' , this . em ( u / nbox . scale ) ) ;
271349 }
272- bbox . clean ( ) ;
350+ if ( v ) {
351+ const denom = this . childNodes [ 1 ] . chtml ;
352+ adaptor . setStyle ( denom , 'verticalAlign' , this . em ( v / dbox . scale ) ) ;
353+ }
354+ const dx = this . em ( - delta / 2 ) ;
355+ adaptor . setStyle ( this . bevel . chtml , 'marginLeft' , dx ) ;
356+ adaptor . setStyle ( this . bevel . chtml , 'marginRight' , dx ) ;
273357 }
274358
275- protected getFractionBBox ( bbox : BBox , t : number ) {
276- const { displaystyle, scriptlevel} = this . node . attributes . getList ( 'displaystyle' , 'scriptlevel' ) ;
277- const display = displaystyle && scriptlevel === 0 ;
359+ /*
360+ * @param {BBox } bbox The boundng box to modify
361+ * @param {boolean } display True for display-mode fractions
362+ */
363+ protected getBevelledBBox ( bbox : BBox , display : boolean ) {
364+ const { u, v, delta, nbox, dbox} = this . getBevelData ( display ) ;
365+ const lbox = this . bevel . getBBox ( ) ;
366+ bbox . combine ( nbox , 0 , u ) ;
367+ bbox . combine ( lbox , bbox . w - delta / 2 , 0 ) ;
368+ bbox . combine ( dbox , bbox . w - delta / 2 , v ) ;
369+ }
370+
371+ /*
372+ * @param {boolean } display True for display-style fractions
373+ * @return {Object } The height (H) of the bevel, horizontal offest (delta)
374+ * vertical offsets (u and v) of the parts, and
375+ * bounding boxes of the parts.
376+ */
377+ protected getBevelData ( display : boolean ) {
278378 const nbox = this . childNodes [ 0 ] . getBBox ( ) ;
279379 const dbox = this . childNodes [ 1 ] . getBBox ( ) ;
280- const fparam = this . font . params ;
281- const pad = ( this . node . getProperty ( 'texWithDelims' ) as boolean ? 0 : fparam . nulldelimiterspace ) ;
282- const a = fparam . axis_height ;
283- const T = ( display ? 3.5 : 1.5 ) * t ;
284- bbox . combine ( nbox , 0 , a + T + Math . max ( nbox . d * nbox . rscale , ( display ? fparam . num1 : fparam . num2 ) - a - T ) ) ;
285- bbox . combine ( dbox , 0 , a - T - Math . max ( dbox . h * dbox . rscale , ( display ? fparam . denom1 : fparam . denom2 ) + a - T ) ) ;
286- bbox . w += 2 * pad + .2 ;
380+ const delta = ( display ? .4 : .15 ) ;
381+ const H = Math . max ( nbox . scale * ( nbox . h + nbox . d ) , dbox . scale * ( dbox . h + dbox . d ) ) + 2 * delta ;
382+ const a = this . font . params . axis_height ;
383+ const u = nbox . scale * ( nbox . d - nbox . h ) / 2 + a + delta ;
384+ const v = dbox . scale * ( dbox . d - dbox . h ) / 2 + a - delta ;
385+ return { H, delta, u, v, nbox, dbox} ;
287386 }
288387
289- protected getAtopBBox ( bbox : BBox ) {
290- const { displaystyle, scriptlevel} = this . node . attributes . getList ( 'displaystyle' , 'scriptlevel' ) ;
291- const display = displaystyle && scriptlevel === 0 ;
292- const fparam = this . font . params ;
293- const pad = ( this . node . getProperty ( 'texWithDelims' ) as boolean ? 0 : fparam . nulldelimiterspace ) ;
294- const { u, v, nbox, dbox} = this . getUVQ ( display ) ;
295- bbox . combine ( nbox , 0 , u ) ;
296- bbox . combine ( dbox , 0 , - v ) ;
297- bbox . w += 2 * pad ;
298- }
299388
300- protected getBevelledBBox ( bbox : BBox ) {
301- }
389+ /************************************************/
302390
303391 /*
304392 * @override
305393 */
306394 public canStretch ( direction : DIRECTION ) {
307395 return false ;
308396 }
397+
398+ /*
399+ * @return {boolean } True if in display mode, false otherwise
400+ */
401+ protected isDisplay ( ) {
402+ const { displaystyle, scriptlevel} = this . node . attributes . getList ( 'displaystyle' , 'scriptlevel' ) ;
403+ return displaystyle && scriptlevel === 0 ;
404+ }
309405}
0 commit comments