@@ -1372,23 +1372,48 @@ end
13721372
13731373function elements .table .output (_ ) end
13741374
1375+ local function getRadicandMode (mode )
1376+ -- Not too sure if we should do something special/
1377+ return mode
1378+ end
1379+
1380+ local function getDegreeMode (mode )
1381+ -- 2 levels smaller, up to scriptScript evntually.
1382+ -- Not too sure if we should do something else.
1383+ if mode == mathMode .display then
1384+ return mathMode .scriptScript
1385+ elseif mode == mathMode .displayCramped then
1386+ return mathMode .scriptScriptCramped
1387+ elseif mode == mathMode .text or mode == mathMode .script or mode == mathMode .scriptScript then
1388+ return mathMode .scriptScript
1389+ end
1390+ return mathMode .scriptScriptCramped
1391+ end
1392+
13751393elements .sqrt = pl .class (elements .mbox )
13761394elements .sqrt ._type = " Sqrt"
13771395
13781396function elements .sqrt :__tostring ()
1379- return self ._type .. " (" .. tostring (self .radicand ) .. " )"
1397+ return self ._type .. " (" .. tostring (self .radicand ) .. ( self . degree and " , " .. tostring ( self . degree ) or " " ) .. " )"
13801398end
13811399
1382- function elements .sqrt :_init (radicand )
1400+ function elements .sqrt :_init (radicand , degree )
13831401 elements .mbox ._init (self )
13841402 self .radicand = radicand
1403+ if degree then
1404+ self .degree = degree
1405+ table.insert (self .children , degree )
1406+ end
13851407 table.insert (self .children , radicand )
1386- self .relX = SILE .types .length (0 ) -- x position relative to its parent box
1387- self .relY = SILE .types .length (0 ) -- y position relative to its parent box
1408+ self .relX = SILE .types .length ()
1409+ self .relY = SILE .types .length ()
13881410end
13891411
13901412function elements .sqrt :styleChildren ()
1391- self .radicand .mode = self .mode
1413+ self .radicand .mode = getRadicandMode (self .mode )
1414+ if self .degree then
1415+ self .degree .mode = getDegreeMode (self .mode )
1416+ end
13921417end
13931418
13941419function elements .sqrt :shape ()
@@ -1404,15 +1429,42 @@ function elements.sqrt:shape ()
14041429 end
14051430 self .extraAscender = constants .radicalExtraAscender * scaleDown
14061431
1407- -- HACK: More or less ad hoc values, see output method for more details
1408- self .symbolWidth = SILE .shaper :measureChar (" √" ).width
1409- self .symbolHeight = SILE .types .length (" 1.1ex" ):tonumber () * scaleDown
1410-
1411- self .width = self .radicand .width + SILE .types .length (self .symbolWidth )
1412- self .height = self .radicand .height + self .radicalVerticalGap + self .extraAscender
1432+ -- HACK: We draw own own radical sign in the output() method.
1433+ -- Derive dimensions for the radical sign (more or less ad hoc).
1434+ -- Note: In TeX, the radical sign extends a lot below the baseline,
1435+ -- and MathML Core also has a lot of layout text about it.
1436+ -- Not only it doesn't look good, but it's not very clear vs. OpenType.
1437+ local radicalGlyph = SILE .shaper :measureChar (" √" )
1438+ local ratio = (self .radicand .height :tonumber () + self .radicand .depth :tonumber ())
1439+ / (radicalGlyph .height + radicalGlyph .depth )
1440+ local vertAdHocOffset = (ratio > 1 and math.log (ratio ) or 0 ) * self .radicalVerticalGap
1441+ self .symbolHeight = SILE .types .length (radicalGlyph .height ) * scaleDown
1442+ self .symbolDepth = (SILE .types .length (radicalGlyph .depth ) + vertAdHocOffset ) * scaleDown
1443+ self .symbolWidth = (SILE .types .length (radicalGlyph .width ) + vertAdHocOffset ) * scaleDown
1444+
1445+ -- Adjust the height of the radical sign if the radicand is higher
1446+ self .symbolHeight = self .radicand .height > self .symbolHeight and self .radicand .height or self .symbolHeight
1447+ -- Compute the (max-)height of the short leg of the radical sign
1448+ self .symbolShortHeight = self .symbolHeight * constants .radicalDegreeBottomRaisePercent
1449+
1450+ self .offsetX = SILE .types .length ()
1451+ if self .degree then
1452+ -- Position the degree
1453+ self .degree .relY = - constants .radicalDegreeBottomRaisePercent * self .symbolHeight
1454+ -- Adjust the height of the short leg of the radical sign to ensure the degree is not too close
1455+ -- (empirically use radicalExtraAscender)
1456+ self .symbolShortHeight = self .symbolShortHeight - constants .radicalExtraAscender * scaleDown
1457+ -- Compute the width adjustment for the degree
1458+ self .offsetX = self .degree .width
1459+ + constants .radicalKernBeforeDegree * scaleDown
1460+ + constants .radicalKernAfterDegree * scaleDown
1461+ end
1462+ -- Position the radicand
1463+ self .radicand .relX = self .symbolWidth + self .offsetX
1464+ -- Compute the dimentions of the whole radical
1465+ self .width = self .radicand .width + self .symbolWidth + self .offsetX
1466+ self .height = self .symbolHeight + self .radicalVerticalGap + self .extraAscender
14131467 self .depth = self .radicand .depth
1414- self .radicand :shape ()
1415- self .radicand .relX = self .symbolWidth
14161468end
14171469
14181470local function _r (number )
@@ -1422,40 +1474,46 @@ local function _r (number)
14221474end
14231475
14241476function elements .sqrt :output (x , y , line )
1425- -- HACK FIXME :
1477+ -- HACK:
14261478 -- OpenType might say we need to assemble the radical sign from parts.
14271479 -- Frankly, it's much easier to just draw it as a graphic :-)
14281480 -- Hence, here we use a PDF graphic operators to draw a nice radical sign.
14291481 -- Some values here are ad hoc, but they look good.
14301482 local h = self .height :tonumber ()
14311483 local d = self .depth :tonumber ()
1432- local sw = self .symbolWidth
1433- local dh = h - self .symbolHeight
1484+ local s0 = scaleWidth (self .offsetX , line ):tonumber ()
1485+ local sw = scaleWidth (self .symbolWidth , line ):tonumber ()
1486+ local dsh = h - self .symbolShortHeight :tonumber ()
1487+ local dsd = self .symbolDepth :tonumber ()
14341488 local symbol = {
14351489 _r (self .radicalRuleThickness ),
14361490 " w" , -- line width
14371491 2 ,
14381492 " j" , -- round line joins
1439- _r (sw ),
1493+ _r (sw + s0 ),
14401494 _r (self .extraAscender ),
14411495 " m" ,
1442- _r (sw * 0.4 ),
1443- _r (h + d ),
1496+ _r (s0 + sw * 0.90 ),
1497+ _r (self .extraAscender ),
1498+ " l" ,
1499+ _r (s0 + sw * 0.4 ),
1500+ _r (h + d + dsd ),
14441501 " l" ,
1445- _r (sw * 0.15 ),
1446- _r (dh ),
1502+ _r (s0 + sw * 0.2 ),
1503+ _r (dsh ),
14471504 " l" ,
1448- 0 ,
1449- _r (dh + 0.5 ),
1505+ s0 + sw * 0.1 ,
1506+ _r (dsh + 0.5 ),
14501507 " l" ,
14511508 " S" ,
14521509 }
14531510 local svg = table.concat (symbol , " " )
1454- SILE .outputter :drawSVG (svg , x , y , sw , h , 1 )
1511+ local xscaled = scaleWidth (x , line )
1512+ SILE .outputter :drawSVG (svg , xscaled , y , sw , h , 1 )
14551513 -- And now we just need to draw the bar over the radicand
14561514 SILE .outputter :drawRule (
1457- self .symbolWidth + scaleWidth ( x , line ) ,
1458- y .length - scaleWidth ( self .radicand . height , line ) - self .radicalVerticalGap - self .radicalRuleThickness / 2 ,
1515+ s0 + self .symbolWidth + xscaled ,
1516+ y .length - self .height + self .extraAscender - self .radicalRuleThickness / 2 ,
14591517 scaleWidth (self .radicand .width , line ),
14601518 self .radicalRuleThickness
14611519 )
0 commit comments