@@ -1334,6 +1334,85 @@ end
13341334
13351335function elements .table .output (_ ) end
13361336
1337+ elements .sqrt = pl .class (elements .mbox )
1338+ elements .sqrt ._type = " Sqrt"
1339+
1340+ function elements .sqrt :__tostring ()
1341+ return self ._type .. " (" .. tostring (self .radicand ) .. " )"
1342+ end
1343+
1344+ function elements .sqrt :_init (radicand )
1345+ elements .mbox ._init (self )
1346+ self .radicand = radicand
1347+ table.insert (self .children , radicand )
1348+ self .relX = SILE .types .length (0 ) -- x position relative to its parent box
1349+ self .relY = SILE .types .length (0 ) -- y position relative to its parent box
1350+ end
1351+
1352+ function elements .sqrt :styleChildren ()
1353+ self .radicand .mode = self .mode
1354+ end
1355+
1356+ function elements .sqrt :shape ()
1357+ local mathMetrics = self :getMathMetrics ()
1358+ local scaleDown = self :getScaleDown ()
1359+ local constants = mathMetrics .constants
1360+
1361+ self .radicalRuleThickness = constants .radicalRuleThickness * scaleDown
1362+ if self .mode == mathMode .display or self .mode == mathMode .displayCramped then
1363+ self .radicalVerticalGap = constants .radicalDisplayStyleVerticalGap * scaleDown
1364+ else
1365+ self .radicalVerticalGap = constants .radicalVerticalGap * scaleDown
1366+ end
1367+ self .extraAscender = constants .radicalExtraAscender * scaleDown
1368+
1369+ -- HACK: More or less ad hoc values, see output method for more details
1370+ self .symbolWidth = SILE .shaper :measureChar (" √" ).width
1371+ self .symbolHeight = SILE .types .length (" 1.1ex" ):tonumber () * scaleDown
1372+
1373+ self .width = self .radicand .width + SILE .types .length (self .symbolWidth )
1374+ self .height = self .radicand .height + self .radicalVerticalGap + self .extraAscender
1375+ self .depth = self .radicand .depth
1376+ self .radicand :shape ()
1377+ self .radicand .relX = self .symbolWidth
1378+ end
1379+
1380+ local function _r (number )
1381+ -- Lua 5.3+ formats floats as 1.0 and integers as 1
1382+ -- Also some PDF readers do not like double precision.
1383+ return math.floor (number ) == number and math.floor (number ) or tonumber (string.format (" %.5f" , number ))
1384+ end
1385+
1386+ function elements .sqrt :output (x , y , line )
1387+ -- HACK FIXME:
1388+ -- OpenType might say we need to assemble the radical sign from parts.
1389+ -- Frankly, it's much easier to just draw it as a graphic :-)
1390+ -- Hence, here we use a PDF graphic operators to draw a nice radical sign.
1391+ -- Some values here are ad hoc, but they look good.
1392+ local h = self .height :tonumber ()
1393+ local d = self .depth :tonumber ()
1394+ local sw = self .symbolWidth
1395+ local dh = h - self .symbolHeight
1396+ local symbol = {
1397+ _r (self .radicalRuleThickness ), " w" , -- line width
1398+ 2 , " j" , -- round line joins
1399+ _r (sw ), _r (self .extraAscender ), " m" ,
1400+ _r (sw * 0.4 ), _r (h + d ), " l" ,
1401+ _r (sw * 0.15 ), _r (dh ), " l" ,
1402+ 0 , _r (dh + 0.5 ), " l" ,
1403+ " S"
1404+ }
1405+ local svg = table.concat (symbol , " " )
1406+ SILE .outputter :drawSVG (svg , x , y , sw , h , 1 )
1407+ -- And now we just need to draw the bar over the radicand
1408+ SILE .outputter :drawRule (
1409+ self .symbolWidth + scaleWidth (x , line ),
1410+ y .length - scaleWidth (self .radicand .height , line ) - self .radicalVerticalGap - self .radicalRuleThickness / 2 ,
1411+ scaleWidth (self .radicand .width , line ),
1412+ self .radicalRuleThickness
1413+ )
1414+ end
1415+
13371416elements .mathMode = mathMode
13381417elements .atomType = atomType
13391418elements .scriptType = scriptType
0 commit comments