diff options
Diffstat (limited to 'macros/luatex/generic/lualibs/lualibs-util-dim.lua')
-rw-r--r-- | macros/luatex/generic/lualibs/lualibs-util-dim.lua | 234 |
1 files changed, 96 insertions, 138 deletions
diff --git a/macros/luatex/generic/lualibs/lualibs-util-dim.lua b/macros/luatex/generic/lualibs/lualibs-util-dim.lua index bb9eca9668..6462f3e492 100644 --- a/macros/luatex/generic/lualibs/lualibs-util-dim.lua +++ b/macros/luatex/generic/lualibs/lualibs-util-dim.lua @@ -6,14 +6,10 @@ if not modules then modules = { } end modules ['util-dim'] = { license = "see context related readme files" } ---[[ldx-- -<p>Internally <l n='luatex'/> work with scaled point, which are -represented by integers. However, in practice, at east at the -<l n='tex'/> end we work with more generic units like points (pt). Going -from scaled points (numbers) to one of those units can be -done by using the conversion factors collected in the following -table.</p> ---ldx]]-- +-- Internally LuaTeX work with scaled point, which are represented by integers. +-- However, in practice, at east at the TeX end we work with more generic units like +-- points (pt). Going from scaled points (numbers) to one of those units can be done +-- by using the conversion factors collected in the following table. local format, match, gsub, type, setmetatable = string.format, string.match, string.gsub, type, setmetatable local P, S, R, Cc, C, lpegmatch = lpeg.P, lpeg.S, lpeg.R, lpeg.Cc, lpeg.C, lpeg.match @@ -45,7 +41,9 @@ local dimenfactors = allocate { ["dd"] = ( 1157/ 1238)/65536, ["cc"] = ( 1157/14856)/65536, -- ["nd"] = (20320/21681)/65536, - -- ["nc"] = ( 5080/65043)/65536 + -- ["nc"] = ( 5080/65043)/65536, + ["es"] = ( 9176/ 129)/65536, + ["ts"] = ( 4588/ 645)/65536, } -- print(table.serialize(dimenfactors)) @@ -86,10 +84,8 @@ local dimenfactors = allocate { -- ["sp"]=1, -- } ---[[ldx-- -<p>A conversion function that takes a number, unit (string) and optional -format (string) is implemented using this table.</p> ---ldx]]-- +-- A conversion function that takes a number, unit (string) and optional format +-- (string) is implemented using this table. local f_none = formatters["%s%s"] local f_true = formatters["%0.5F%s"] @@ -110,9 +106,7 @@ local function numbertodimen(n,unit,fmt) -- will be redefined later ! end end ---[[ldx-- -<p>We collect a bunch of converters in the <type>number</type> namespace.</p> ---ldx]]-- +-- We collect a bunch of converters in the 'number' namespace. number.maxdimen = 1073741823 number.todimen = numbertodimen @@ -122,7 +116,7 @@ function number.topoints (n,fmt) return numbertodimen(n,"pt",fmt) end function number.toinches (n,fmt) return numbertodimen(n,"in",fmt) end function number.tocentimeters (n,fmt) return numbertodimen(n,"cm",fmt) end function number.tomillimeters (n,fmt) return numbertodimen(n,"mm",fmt) end -function number.toscaledpoints(n,fmt) return numbertodimen(n,"sp",fmt) end +-------- number.toscaledpoints(n,fmt) return numbertodimen(n,"sp",fmt) end function number.toscaledpoints(n) return n .. "sp" end function number.tobasepoints (n,fmt) return numbertodimen(n,"bp",fmt) end function number.topicas (n,fmt) return numbertodimen(n "pc",fmt) end @@ -130,14 +124,13 @@ function number.todidots (n,fmt) return numbertodimen(n,"dd",fmt) end function number.tociceros (n,fmt) return numbertodimen(n,"cc",fmt) end -------- number.tonewdidots (n,fmt) return numbertodimen(n,"nd",fmt) end -------- number.tonewciceros (n,fmt) return numbertodimen(n,"nc",fmt) end +function number.toediths (n,fmt) return numbertodimen(n,"es",fmt) end +function number.totoves (n,fmt) return numbertodimen(n,"ts",fmt) end ---[[ldx-- -<p>More interesting it to implement a (sort of) dimen datatype, one -that permits calculations too. First we define a function that -converts a string to scaledpoints. We use <l n='lpeg'/>. We capture -a number and optionally a unit. When no unit is given a constant -capture takes place.</p> ---ldx]]-- +-- More interesting it to implement a (sort of) dimen datatype, one that permits +-- calculations too. First we define a function that converts a string to +-- scaledpoints. We use LPEG. We capture a number and optionally a unit. When no +-- unit is given a constant capture takes place. local amount = (S("+-")^0 * R("09")^0 * P(".")^0 * R("09")^0) + Cc("0") local unit = R("az")^1 + P("%") @@ -152,21 +145,16 @@ function number.splitdimen(str) return lpegmatch(splitter,str) end ---[[ldx-- -<p>We use a metatable to intercept errors. When no key is found in -the table with factors, the metatable will be consulted for an -alternative index function.</p> ---ldx]]-- +-- We use a metatable to intercept errors. When no key is found in the table with +-- factors, the metatable will be consulted for an alternative index function. setmetatableindex(dimenfactors, function(t,s) -- error("wrong dimension: " .. (s or "?")) -- better a message return false end) ---[[ldx-- -<p>We redefine the following function later on, so we comment it -here (which saves us bytecodes.</p> ---ldx]]-- +-- We redefine the following function later on, so we comment it here (which saves +-- us bytecodes. -- function string.todimen(str) -- if type(str) == "number" then @@ -182,44 +170,38 @@ here (which saves us bytecodes.</p> local stringtodimen -- assigned later (commenting saves bytecode) local amount = S("+-")^0 * R("09")^0 * S(".,")^0 * R("09")^0 -local unit = P("pt") + P("cm") + P("mm") + P("sp") + P("bp") + P("in") + - P("pc") + P("dd") + P("cc") + P("nd") + P("nc") +local unit = P("pt") + P("cm") + P("mm") + P("sp") + P("bp") + + P("es") + P("ts") + P("pc") + P("dd") + P("cc") + + P("in") + -- + P("nd") + P("nc") local validdimen = amount * unit lpeg.patterns.validdimen = validdimen ---[[ldx-- -<p>This converter accepts calls like:</p> - -<typing> -string.todimen("10") -string.todimen(".10") -string.todimen("10.0") -string.todimen("10.0pt") -string.todimen("10pt") -string.todimen("10.0pt") -</typing> - -<p>With this in place, we can now implement a proper datatype for dimensions, one -that permits us to do this:</p> - -<typing> -s = dimen "10pt" + dimen "20pt" + dimen "200pt" - - dimen "100sp" / 10 + "20pt" + "0pt" -</typing> - -<p>We create a local metatable for this new type:</p> ---ldx]]-- +-- This converter accepts calls like: +-- +-- string.todimen("10") +-- string.todimen(".10") +-- string.todimen("10.0") +-- string.todimen("10.0pt") +-- string.todimen("10pt") +-- string.todimen("10.0pt") +-- +-- With this in place, we can now implement a proper datatype for dimensions, one +-- that permits us to do this: +-- +-- s = dimen "10pt" + dimen "20pt" + dimen "200pt" +-- - dimen "100sp" / 10 + "20pt" + "0pt" +-- +-- We create a local metatable for this new type: local dimensions = { } ---[[ldx-- -<p>The main (and globally) visible representation of a dimen is defined next: it is -a one-element table. The unit that is returned from the match is normally a number -(one of the previously defined factors) but we also accept functions. Later we will -see why. This function is redefined later.</p> ---ldx]]-- +-- The main (and globally) visible representation of a dimen is defined next: it is +-- a one-element table. The unit that is returned from the match is normally a +-- number (one of the previously defined factors) but we also accept functions. +-- Later we will see why. This function is redefined later. -- function dimen(a) -- if a then @@ -241,11 +223,9 @@ see why. This function is redefined later.</p> -- end -- end ---[[ldx-- -<p>This function return a small hash with a metatable attached. It is -through this metatable that we can do the calculations. We could have -shared some of the code but for reasons of speed we don't.</p> ---ldx]]-- +-- This function return a small hash with a metatable attached. It is through this +-- metatable that we can do the calculations. We could have shared some of the code +-- but for reasons of speed we don't. function dimensions.__add(a, b) local ta, tb = type(a), type(b) @@ -281,20 +261,16 @@ function dimensions.__unm(a) return setmetatable({ - a }, dimensions) end ---[[ldx-- -<p>It makes no sense to implement the power and modulo function but -the next two do make sense because they permits is code like:</p> - -<typing> -local a, b = dimen "10pt", dimen "11pt" -... -if a > b then - ... -end -</typing> ---ldx]]-- - --- makes no sense: dimensions.__pow and dimensions.__mod +-- It makes no sense to implement the power and modulo function but +-- the next two do make sense because they permits is code like: +-- +-- local a, b = dimen "10pt", dimen "11pt" +-- ... +-- if a > b then +-- ... +-- end +-- +-- This also makes no sense: dimensions.__pow and dimensions.__mod. function dimensions.__lt(a, b) return a[1] < b[1] @@ -304,24 +280,17 @@ function dimensions.__eq(a, b) return a[1] == b[1] end ---[[ldx-- -<p>We also need to provide a function for conversion to string (so that -we can print dimensions). We print them as points, just like <l n='tex'/>.</p> ---ldx]]-- +-- We also need to provide a function for conversion to string (so that we can print +-- dimensions). We print them as points, just like TeX. function dimensions.__tostring(a) return a[1]/65536 .. "pt" -- instead of todimen(a[1]) end ---[[ldx-- -<p>Since it does not take much code, we also provide a way to access -a few accessors</p> - -<typing> -print(dimen().pt) -print(dimen().sp) -</typing> ---ldx]]-- +-- Since it does not take much code, we also provide a way to access a few accessors +-- +-- print(dimen().pt) +-- print(dimen().sp) function dimensions.__index(tab,key) local d = dimenfactors[key] @@ -332,41 +301,34 @@ function dimensions.__index(tab,key) return 1/d end ---[[ldx-- -<p>In the converter from string to dimension we support functions as -factors. This is because in <l n='tex'/> we have a few more units: -<type>ex</type> and <type>em</type>. These are not constant factors but -depend on the current font. They are not defined by default, but need -an explicit function call. This is because at the moment that this code -is loaded, the relevant tables that hold the functions needed may not -yet be available.</p> ---ldx]]-- - - dimenfactors["ex"] = 4 * 1/65536 -- 4pt - dimenfactors["em"] = 10 * 1/65536 -- 10pt --- dimenfactors["%"] = 4 * 1/65536 -- 400pt/100 - ---[[ldx-- -<p>The previous code is rather efficient (also thanks to <l n='lpeg'/>) but we -can speed it up by caching converted dimensions. On my machine (2008) the following -loop takes about 25.5 seconds.</p> - -<typing> -for i=1,1000000 do - local s = dimen "10pt" + dimen "20pt" + dimen "200pt" - - dimen "100sp" / 10 + "20pt" + "0pt" -end -</typing> - -<p>When we cache converted strings this becomes 16.3 seconds. In order not -to waste too much memory on it, we tag the values of the cache as being -week which mean that the garbage collector will collect them in a next -sweep. This means that in most cases the speed up is mostly affecting the -current couple of calculations and as such the speed penalty is small.</p> - -<p>We redefine two previous defined functions that can benefit from -this:</p> ---ldx]]-- +-- In the converter from string to dimension we support functions as factors. This +-- is because in TeX we have a few more units: 'ex' and 'em'. These are not constant +-- factors but depend on the current font. They are not defined by default, but need +-- an explicit function call. This is because at the moment that this code is +-- loaded, the relevant tables that hold the functions needed may not yet be +-- available. + + dimenfactors["ex"] = 4 /65536 -- 4pt + dimenfactors["em"] = 10 /65536 -- 10pt +-- dimenfactors["%"] = 4 /65536 -- 400pt/100 + dimenfactors["eu"] = (9176/129)/65536 -- 1es + +-- The previous code is rather efficient (also thanks to LPEG) but we can speed it +-- up by caching converted dimensions. On my machine (2008) the following loop takes +-- about 25.5 seconds. +-- +-- for i=1,1000000 do +-- local s = dimen "10pt" + dimen "20pt" + dimen "200pt" +-- - dimen "100sp" / 10 + "20pt" + "0pt" +-- end +-- +-- When we cache converted strings this becomes 16.3 seconds. In order not to waste +-- too much memory on it, we tag the values of the cache as being week which mean +-- that the garbage collector will collect them in a next sweep. This means that in +-- most cases the speed up is mostly affecting the current couple of calculations +-- and as such the speed penalty is small. +-- +-- We redefine two previous defined functions that can benefit from this: local known = { } setmetatable(known, { __mode = "v" }) @@ -436,14 +398,10 @@ function number.toscaled(d) return format("%0.5f",d/0x10000) -- 2^16 end ---[[ldx-- -<p>In a similar fashion we can define a glue datatype. In that case we -probably use a hash instead of a one-element table.</p> ---ldx]]-- - ---[[ldx-- -<p>Goodie:s</p> ---ldx]]-- +-- In a similar fashion we can define a glue datatype. In that case we probably use +-- a hash instead of a one-element table. +-- +-- A goodie: function number.percent(n,d) -- will be cleaned up once luatex 0.30 is out d = d or texget("hsize") |