if not modules then modules = { } end modules ['typo-brk'] = { version = 1.001, comment = "companion to typo-brk.mkiv", author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", copyright = "PRAGMA ADE / ConTeXt Development Team", license = "see context related readme files" } -- this code dates from the beginning and is kind of experimental; it -- will be optimized and improved soon local next, type = next, type local format = string.format local has_attribute = node.has_attribute local unset_attribute = node.unset_attribute local set_attribute = node.set_attribute local copy_node = node.copy local insert_node_before = node.insert_before local insert_node_after = node.insert_after local make_penalty_node = nodes.penalty local make_glue_node = nodes.glue local make_disc_node = nodes.disc local glyph = node.id("glyph") local kern = node.id("kern") breakpoints = breakpoints or { } breakpoints.mapping = breakpoints.mapping or { } breakpoints.methods = breakpoints.methods or { } breakpoints.attribute = attributes.private("breakpoint") storage.register("breakpoints/mapping", breakpoints.mapping, "breakpoints.mapping") local mapping = breakpoints.mapping function breakpoints.setreplacement(id,char,kind,before,after,language) local map = mapping[id] if not map then map = { } mapping[id] = map end local cmap = map[char] if not cmap then cmap = { } map[char] = cmap end cmap[language or ""] = { kind or 1, before or 1, after or 1 } end breakpoints.methods[1] = function(head,start) if start.prev and start.next then insert_node_before(head,start,make_penalty_node(10000)) insert_node_before(head,start,make_glue_node(0)) insert_node_after(head,start,make_glue_node(0)) insert_node_after(head,start,make_penalty_node(0)) end return head, start end breakpoints.methods[2] = function(head,start) -- ( => (- if start.prev and start.next then local tmp = start start = make_disc_node() start.prev, start.next = tmp.prev, tmp.next tmp.prev.next, tmp.next.prev = start, start tmp.prev, tmp.next = nil, nil start.replace = tmp local tmp, hyphen = copy_node(tmp), copy_node(tmp) hyphen.char = languages.prehyphenchar(tmp.lang) tmp.next, hyphen.prev = hyphen, tmp start.post = tmp insert_node_before(head,start,make_penalty_node(10000)) insert_node_before(head,start,make_glue_node(0)) insert_node_after(head,start,make_glue_node(0)) insert_node_after(head,start,make_penalty_node(10000)) end return head, start end breakpoints.methods[3] = function(head,start) -- ) => -) if start.prev and start.next then local tmp = start start = make_disc_node() start.prev, start.next = tmp.prev, tmp.next tmp.prev.next, tmp.next.prev = start, start tmp.prev, tmp.next = nil, nil start.replace = tmp local tmp, hyphen = copy_node(tmp), copy_node(tmp) hyphen.char = languages.prehyphenchar(tmp.lang) tmp.prev, hyphen.next = hyphen, tmp start.pre = hyphen insert_node_before(head,start,make_penalty_node(10000)) insert_node_before(head,start,make_glue_node(0)) insert_node_after(head,start,make_glue_node(0)) insert_node_after(head,start,make_penalty_node(10000)) end return head, start end breakpoints.methods[4] = function(head,start) -- - => - - - if start.prev and start.next then local tmp = start start = make_disc_node() start.prev, start.next = tmp.prev, tmp.next tmp.prev.next, tmp.next.prev = start, start tmp.prev, tmp.next = nil, nil -- maybe prehyphenchar etc start.pre = copy_node(tmp) start.post = copy_node(tmp) start.replace = tmp insert_node_before(head,start,make_penalty_node(10000)) insert_node_before(head,start,make_glue_node(0)) insert_node_after(head,start,make_glue_node(0)) insert_node_after(head,start,make_penalty_node(10000)) end return head, start end local methods = breakpoints.methods function breakpoints.process(namespace,attribute,head) local done, numbers = false, languages.numbers local start, n = head, 0 while start do local id = start.id if id == glyph then local attr = has_attribute(start,attribute) if attr and attr > 0 then unset_attribute(start,attribute) -- maybe test for subtype > 256 (faster) -- look ahead and back n chars local map = mapping[attr] if map then local cmap = map[start.char] if cmap then local lang = start.lang -- we do a sanity check for language local smap = lang and lang >= 0 and lang < 0x7FFF and (cmap[numbers[lang]] or cmap[""]) if smap then if n >= smap[2] then local m = smap[3] local next = start.next while next do -- gamble on same attribute local id = next.id if id == glyph then -- gamble on same attribute if map[next.char] then break elseif m == 1 then local method = methods[smap[1]] if method then head, start = method(head,start) done = true end break else m = m - 1 next = next.next end elseif id == kern and next.subtype == 0 then next = next.next -- ignore intercharacter kerning, will go way else -- we can do clever and set n and jump ahead but ... not now break end end end n = 0 else n = n + 1 end else n = n + 1 end else n = 0 end end elseif id == kern and start.subtype == 0 then -- ignore intercharacter kerning, will go way else n = 0 end start = start.next end return head, done end chars.handle_breakpoints = nodes.install_attribute_handler { name = "breakpoint", namespace = breakpoints, processor = breakpoints.process, } function breakpoints.enable() tasks.enableaction("processors","chars.handle_breakpoints") end