diff options
Diffstat (limited to 'tex/context/base/typo-drp.lua')
| -rw-r--r-- | tex/context/base/typo-drp.lua | 405 | 
1 files changed, 336 insertions, 69 deletions
| diff --git a/tex/context/base/typo-drp.lua b/tex/context/base/typo-drp.lua index 903140dae..4bbf0b8e9 100644 --- a/tex/context/base/typo-drp.lua +++ b/tex/context/base/typo-drp.lua @@ -11,9 +11,7 @@ if not modules then modules = { } end modules ['typo-drp'] = {  local tonumber, type, next = tonumber, type, next  local ceil = math.ceil - -local utfbyte = utf.byte -local utfchar = utf.char +local settings_to_hash = utilities.parsers.settings_to_hash  local trace_initials    = false  trackers.register("typesetters.initials", function(v) trace_initials = v end)  local report_initials   = logs.reporter("nodes","initials") @@ -24,19 +22,41 @@ typesetters.initials    = initials or { }  local nodes             = nodes  local tasks             = nodes.tasks -local hpack_nodes       = nodes.hpack +local nuts              = nodes.nuts +local tonut             = nuts.tonut +local tonode            = nuts.tonode + +local getnext           = nuts.getnext +local getprev           = nuts.getprev +local getchar           = nuts.getchar +local getid             = nuts.getid +local getsubtype        = nuts.getsubtype +local getfield          = nuts.getfield +local setfield          = nuts.setfield +local getattr           = nuts.getattr +local setattr           = nuts.setattr + +local hpack_nodes       = nuts.hpack +  local nodecodes         = nodes.nodecodes  local whatsitcodes      = nodes.whatsitcodes -local nodepool          = nodes.pool +local nodepool          = nuts.pool  local new_kern          = nodepool.kern -local insert_before     = nodes.insert_before -local insert_after      = nodes.insert_after +local insert_before     = nuts.insert_before +local insert_after      = nuts.insert_after +local remove_node       = nuts.remove +local traverse_id       = nuts.traverse_id +local traverse          = nuts.traverse +local free_node         = nuts.free  local variables         = interfaces.variables  local v_default         = variables.default  local v_margin          = variables.margin +local v_auto            = variables.auto +local v_first           = variables.first +local v_last            = variables.last  local texget            = tex.get  local texsetattribute   = tex.setattribute @@ -44,7 +64,8 @@ local unsetvalue        = attributes.unsetvalue  local glyph_code        = nodecodes.glyph  local hlist_code        = nodecodes.hlist -local kern_node         = nodecodes.kern +local glue_code         = nodecodes.glue +local kern_code         = nodecodes.kern  local whatsit_code      = nodecodes.whatsit  local localpar_code     = whatsitcodes.localpar @@ -56,6 +77,8 @@ local a_color           = attributes.private('color')  local a_transparency    = attributes.private('transparency')  local a_colorspace      = attributes.private('colormodel') +local category          = characters.category +  local settings          = nil  function initials.set(specification) @@ -68,7 +91,27 @@ function initials.set(specification)      texsetattribute(a_initial,1)  end -commands.setinitial = initials.set +interfaces.implement { +    name      = "setinitial", +    actions   = initials.set, +    arguments = { +        { +            { "location" }, +            { "enabled", "boolean" }, +            { "method" }, +            { "distance" ,"dimen" }, +            { "hoffset" ,"dimen" }, +            { "voffset" ,"dimen" }, +            { "font", "integer" }, +            { "dynamic", "integer" }, +            { "ca", "integer" }, +            { "ma", "integer" }, +            { "ta", "integer" }, +            { "n", "integer" }, +            { "m", "integer" }, +        } +    } +}  -- dropped caps experiment (will be done properly when luatex  -- stores the state in the local par node) .. btw, search still @@ -84,74 +127,297 @@ commands.setinitial = initials.set  -- todo: prevent linebreak .. but normally a initial ends up at the top of  -- a page so this has a low priority +-- actions[v_default] = function(head,setting) +--     local done = false +--     if getid(head) == whatsit_code and getsubtype(head) == localpar_code then +--         -- begin of par +--         local first = getnext(head) +--         -- parbox .. needs to be set at 0 +--         if first and getid(first) == hlist_code then +--             first = getnext(first) +--         end +--         -- we need to skip over kerns and glues (signals) +--         while first and getid(first) ~= glyph_code do +--             first = getnext(first) +--         end +--         if first and getid(first) == glyph_code then +--             local char = getchar(first) +--             local prev = getprev(first) +--             local next = getnext(first) +--          -- if getid(prev) == hlist_code then +--          --     -- set the width to 0 +--          -- end +--             if next and getid(next) == kern_code then +--                 setfield(next,"kern",0) +--             end +--             if setting.font then +--                 setfield(first,"font",setting.font) +--             end +--             if setting.dynamic > 0 then +--                 setattr(first,0,setting.dynamic) +--             end +--             -- can be a helper +--             local ma = setting.ma or 0 +--             local ca = setting.ca +--             local ta = setting.ta +--             if ca and ca > 0 then +--                 setattr(first,a_colorspace,ma == 0 and 1 or ma) +--                 setattr(first,a_color,ca) +--             end +--             if ta and ta > 0 then +--                 setattr(first,a_transparency,ta) +--             end +--             -- +--             local width     = getfield(first,"width") +--             local height    = getfield(first,"height") +--             local depth     = getfield(first,"depth") +--             local distance  = setting.distance or 0 +--             local voffset   = setting.voffset or 0 +--             local hoffset   = setting.hoffset or 0 +--             local parindent = tex.parindent +--             local baseline  = texget("baselineskip").width +--             local lines     = tonumber(setting.n) or 0 +--             -- +--             setfield(first,"xoffset",- width  - hoffset - distance - parindent) +--             setfield(first,"yoffset",- voffset) -- no longer - height here +--             -- We pack so that successive handling cannot touch the dropped cap. Packaging +--             -- in a hlist is also needed because we cannot locally adapt e.g. parindent (not +--             -- yet stored in with localpar). +--             setfield(first,"prev",nil) +--             setfield(first,"next",nil) +--             local h = hpack_nodes(first) +--             setfield(h,"width",0) +--             setfield(h,"height",0) +--             setfield(h,"depth",0) +--             setfield(prev,"next",h) +--             setfield(next,"prev",h) +--             setfield(h,"next",next) +--             setfield(h,"prev",prev) +--             first = h +--             -- end of packaging +--             if setting.location == v_margin then +--                 -- okay +--             else +--                 if lines == 0 then -- safeguard, not too precise +--                     lines = ceil((height+voffset) / baseline) +--                 end +--                 -- We cannot set parshape yet ... when we can I'll add a slope +--                 -- option (positive and negative, in emwidth). +--                 local hangafter  = - lines +--                 local hangindent = width + distance + parindent +--                 if trace_initials then +--                     report_initials("setting hangafter to %i and hangindent to %p",hangafter,hangindent) +--                 end +--                 tex.hangafter  = hangafter +--                 tex.hangindent = hangindent +--                 if parindent ~= 0 then +--                     insert_after(first,first,new_kern(-parindent)) +--                 end +--             end +--             done = true +--         end +--     end +--     return head, done +-- end +  actions[v_default] = function(head,setting)      local done = false -    if head.id == whatsit_code and head.subtype == localpar_code then +    if getid(head) == whatsit_code and getsubtype(head) == localpar_code then          -- begin of par -        local first = head.next +        local first  = getnext(head) +        local indent = false          -- parbox .. needs to be set at 0 -        if first and first.id == hlist_code then -            first = first.next +        if first and getid(first) == hlist_code then +            first  = getnext(first) +            indent = true          end          -- we need to skip over kerns and glues (signals) -        while first and first.id ~= glyph_code do -            first = first.next +        while first and getid(first) ~= glyph_code do +            first = getnext(first)          end -        if first and first.id == glyph_code then -            local char = first.char -            local prev = first.prev -            local next = first.next -         -- if prev.id == hlist_code then -         --     -- set the width to 0 -         -- end -            if next and next.id == kern_node then -                next.kern = 0 -            end -            if setting.font then -                first.font = setting.font -            end -            if setting.dynamic > 0 then -                first[0] = setting.dynamic -            end -            -- can be a helper -            local ma = setting.ma or 0 -            local ca = setting.ca -            local ta = setting.ta -            if ca and ca > 0 then -                first[a_colorspace] = ma == 0 and 1 or ma -                first[a_color] = ca -            end -            if ta and ta > 0 then -                first[a_transparency] = ta -            end -            -- -            local width     = first.width -            local height    = first.height -            local depth     = first.depth +        if first and getid(first) == glyph_code then +            local ma        = setting.ma or 0 +            local ca        = setting.ca +            local ta        = setting.ta +            local last      = first              local distance  = setting.distance or 0              local voffset   = setting.voffset or 0              local hoffset   = setting.hoffset or 0              local parindent = tex.parindent              local baseline  = texget("baselineskip").width              local lines     = tonumber(setting.n) or 0 +            local dynamic   = setting.dynamic +            local font      = setting.font +            local method    = settings_to_hash(setting.method) +            local length    = tonumber(setting.m) or 1              -- -            first.xoffset   = - width  - hoffset - distance - parindent -            first.yoffset   = - voffset -- no longer - height here  +            -- 1 char | n chars | skip first quote | ignore punct | keep punct +            -- +            if getattr(first,a_initial) then +                for current in traverse(getnext(first)) do +                    if getattr(current,a_initial) then +                        last = current +                    else +                        break +                    end +                end +            elseif method[v_auto] then +                local char = getchar(first) +                local kind = category(char) +                if kind == "po" or kind == "pi" then +                    if method[v_first] then +                        -- remove quote etc before initial +                        local next = getnext(first) +                        if not next then +                            -- don't start with a quote or so +                            return head, false +                        end +                        last = nil +                        for current in traverse_id(glyph_code,next) do +                            head, first = remove_node(head,first,true) +                            first = current +                            last = first +                            break +                        end +                        if not last then +                            -- no following glyph or so +                            return head, false +                        end +                    else +                        -- keep quote etc with initial +                        local next = getnext(first) +                        if not next then +                            -- don't start with a quote or so +                            return head, false +                        end +                        for current in traverse_id(glyph_code,next) do +                            last = current +                            break +                        end +                        if last == first then +                            return head, false +                        end +                    end +                elseif kind == "pf" then +                    -- error: final quote +                else +                    -- okay +                end +                -- maybe also: get all A. B. etc +                local next = getnext(first) +                if next then +                    for current in traverse_id(glyph_code,next) do +                        local char = getchar(current) +                        local kind = category(char) +                        if kind == "po" then +                            if method[v_last] then +                                -- remove period etc after initial +                                remove_node(head,current,true) +                            else +                                -- keep period etc with initial +                                last = current +                            end +                        end +                        break +                    end +                end +            else +                for current in traverse_id(glyph_code,first) do +                    last = current +                    if length <= 1 then +                        break +                    else +                        length = length - 1 +                    end +                end +            end +            local current = first +            while true do +                local id = getid(current) +                if id == kern_code then +                    setfield(current,"kern",0) +                elseif id == glyph_code then +                    local next = getnext(current) +                    if font then +                        setfield(current,"font",font) +                    end +                    if dynamic > 0 then +                        setattr(current,0,dynamic) +                    end +-- apply font + +-- local g = nodes.copy(tonode(current)) +-- g.subtype = 0 +-- nodes.handlers.characters(g) +-- nodes.handlers.protectglyphs(g) +-- setfield(current,"char",g.char) +-- nodes.free(g) + +                    -- can be a helper +                    if ca and ca > 0 then +                        setattr(current,a_colorspace,ma == 0 and 1 or ma) +                        setattr(current,a_color,ca) +                    end +                    if ta and ta > 0 then +                        setattr(current,a_transparency,ta) +                    end +                    -- +                end +                if current == last then +                    break +                else +                    current = getnext(current) +                end +            end              -- We pack so that successive handling cannot touch the dropped cap. Packaging              -- in a hlist is also needed because we cannot locally adapt e.g. parindent (not              -- yet stored in with localpar). -            first.prev = nil -            first.next = nil -            local h = hpack_nodes(first) -            h.width = 0 -            h.height = 0 -            h.depth = 0 -            prev.next = h -            next.prev = h -            h.next = next -            h.prev = prev - -            -- end of packaging +            local prev = getprev(first) +            local next = getnext(last) +            -- +            setfield(first,"prev",nil) +            setfield(last,"next",nil) +            local dropper = hpack_nodes(first) +            local width   = getfield(dropper,"width") +            local height  = getfield(dropper,"height") +            local depth   = getfield(dropper,"depth") +            setfield(dropper,"width",0) +            setfield(dropper,"height",0) +            setfield(dropper,"depth",0) +            -- +            setfield(prev,"next",dropper) +            if next then +                setfield(next,"prev",dropper) +            end +            setfield(dropper,"next",next) +            setfield(dropper,"prev",prev) +            -- +            if next then +                local current = next +                while current do +                    local id = getid(current) +                    if id == glue_code or id == kern_code then +                        local next = getnext(current) +                     -- remove_node(current,current,true) -- created an invalid next link and dangling remains +                        remove_node(head,current,true) +                        current = next +                    else +                        break +                    end +                end +            end +            -- +            local hoffset = width + hoffset + distance + (indent and parindent or 0) +            for current in traverse_id(glyph_code,first) do +                setfield(current,"xoffset",- hoffset ) +                setfield(current,"yoffset",- voffset) -- no longer - height here +                if current == last then +                    break +                end +            end +            -- +            first = dropper +            --              if setting.location == v_margin then                  -- okay              else @@ -161,15 +427,15 @@ actions[v_default] = function(head,setting)                  -- We cannot set parshape yet ... when we can I'll add a slope                  -- option (positive and negative, in emwidth).                  local hangafter  = - lines -                local hangindent = width + distance + parindent +                local hangindent = width + distance                  if trace_initials then                      report_initials("setting hangafter to %i and hangindent to %p",hangafter,hangindent)                  end                  tex.hangafter  = hangafter                  tex.hangindent = hangindent -                if parindent ~= 0 then -                    insert_after(first,first,new_kern(-parindent)) -                end +            end +            if indent then +                insert_after(first,first,new_kern(-parindent))              end              done = true          end @@ -178,16 +444,17 @@ actions[v_default] = function(head,setting)  end  function initials.handler(head) +    head = tonut(head)      local start = head      local attr  = nil      while start do -        attr = start[a_initial] +        attr = getattr(start,a_initial)          if attr then              break -        elseif start.id == glyph then +        elseif getid(start) == glyph then              break          else -            start = start.next +            start = getnext(start)          end      end      if attr then @@ -201,8 +468,8 @@ function initials.handler(head)                  report_initials("processing initials, alternative %a",alternative)              end              local head, done = action(head,settings) -            return head, done +            return tonode(head), done          end      end -    return head, false +    return tonode(head), false  end | 
