diff options
-rw-r--r-- | src/luaotfload-colors.lua | 235 | ||||
-rw-r--r-- | src/luaotfload-configuration.lua | 2 | ||||
-rw-r--r-- | src/luaotfload.sty | 20 |
3 files changed, 168 insertions, 89 deletions
diff --git a/src/luaotfload-colors.lua b/src/luaotfload-colors.lua index 9be2974..0832083 100644 --- a/src/luaotfload-colors.lua +++ b/src/luaotfload-colors.lua @@ -22,19 +22,28 @@ explanation: http://tug.org/pipermail/luatex/2013-May/004305.html local log = luaotfload.log local logreport = log.report -local newnode = node.new -local nodetype = node.id -local traverse_nodes = node.traverse -local insert_node_before = node.insert_before -local insert_node_after = node.insert_after +local nodedirect = node.direct +local newnode = nodedirect.new +local insert_node_before = nodedirect.insert_before +local insert_node_after = nodedirect.insert_after +local todirect = nodedirect.todirect +local tonode = nodedirect.tonode +local setfield = nodedirect.setfield +local getid = nodedirect.getid +local getfont = nodedirect.getfont +local getlist = nodedirect.getlist +local getsubtype = nodedirect.getsubtype +local getnext = nodedirect.getnext +local nodetail = nodedirect.tail +local getattribute = nodedirect.has_attribute +local setattribute = nodedirect.set_attribute local texset = tex.set local texget = tex.get +local texsettoks = tex.settoks +local texgettoks = tex.gettoks local stringformat = string.format -local stringgsub = string.gsub -local stringfind = string.find -local stringsub = string.sub local otffeatures = fonts.constructors.newfeatures("otf") local identifiers = fonts.hashes.identifiers @@ -66,10 +75,11 @@ local lpegmatch = lpeg.match local C, Cg, Ct, P, R, S = lpeg.C, lpeg.Cg, lpeg.Ct, lpeg.P, lpeg.R, lpeg.S local digit16 = R("09", "af", "AF") +local opaque = S("fF") * S("fF") local octet = C(digit16 * digit16) local p_rgb = octet * octet * octet -local p_rgba = p_rgb * octet +local p_rgba = p_rgb * (octet - opaque) local valid_digits = C(p_rgba + p_rgb) -- matches eight or six hex digits local p_Crgb = Cg(octet/hex_to_dec, "red") --- for captures @@ -174,143 +184,194 @@ end --- Luatex internal types +local nodetype = node.id local glyph_t = nodetype("glyph") local hlist_t = nodetype("hlist") local vlist_t = nodetype("vlist") local whatsit_t = nodetype("whatsit") -local page_insert_t = nodetype("page_insert") -local sub_box_t = nodetype("sub_box") - ---- node -> nil | -1 | color‽ -local lookup_next_color -lookup_next_color = function (head) --- paragraph material - for n in traverse_nodes(head) do - local n_id = n.id - - if n_id == glyph_t then - local n_font - if identifiers[n_font] - and identifiers[n_font].properties - and identifiers[n_font].properties.color - then - return identifiers[n.font].properties.color - else - return -1 - end - - elseif n_id == vlist_t or n_id == hlist_t or n_id == sub_box_t then - local r = lookup_next_color(n.list) - if r then - return r - end - - elseif n_id == whatsit_t or n_id == page_insert_t then - return -1 +local disc_t = nodetype("disc") +local pdfliteral_t = node.subtype("pdf_literal") +local colorstack_t = node.subtype("pdf_colorstack") + +local color_callback +local color_attr = luatexbase.new_attribute("luaotfload_color_attribute") + +-- (node * node * string * bool * (bool | nil)) -> (node * node * (string | nil)) +local color_whatsit +color_whatsit = function (head, curr, color, push, tail) + local pushdata = hex_to_rgba(color) + local colornode = newnode(whatsit_t, colorstack_t) + setfield(colornode, "stack", 0) + setfield(colornode, "command", push and 1 or 2) -- 1: push, 2: pop + setfield(colornode, "data", push and pushdata or nil) + if tail then + head, curr = insert_node_after (head, curr, colornode) + else + head = insert_node_before(head, curr, colornode) + end + if not push and color:len() > 6 then + local colornode = newnode(whatsit_t, pdfliteral_t) + setfield(colornode, "mode", 2) + setfield(colornode, "data", "/TransGs1 gs") + if tail then + head, curr = insert_node_after (head, curr, colornode) + else + head = insert_node_before(head, curr, colornode) end end - return nil + color = push and color or nil + return head, curr, color +end + +-- number -> string | nil +local get_font_color = function (font_id) + local tfmdata = identifiers[font_id] + local font_color = tfmdata and tfmdata.properties and tfmdata.properties.color + return font_color end +local cnt = 0 + --[[doc-- While the second argument and second returned value are apparently always nil when the function is called, they temporarily take string values during the node list traversal. --doc]]-- -local cnt = 0 ---- node -> string -> int -> (node * string) +--- (node * (string | nil)) -> (node * (string | nil)) local node_colorize -node_colorize = function (head, current_color, next_color) - for n in traverse_nodes(head) do - local n_id = n.id - local nextnode = n.next - - if n_id == hlist_t or n_id == vlist_t or n_id == sub_box_t then - local next_color_in = lookup_next_color(nextnode) or next_color - n.list, current_color = node_colorize(n.list, current_color, next_color_in) +node_colorize = function (head, current_color) + local n = head + while n do + local n_id = getid(n) - elseif n_id == glyph_t then + if n_id == hlist_t or n_id == vlist_t then cnt = cnt + 1 - local tfmdata = identifiers[n.font] + local n_list = getlist(n) + if getattribute(n_list, color_attr) then + if current_color then + head, n, current_color = color_whatsit(head, n, current_color, false) + end + else + n_list, current_color = node_colorize(n_list, current_color) + if current_color and getsubtype(n) == 1 then -- created by linebreak + n_list, _, current_color = color_whatsit(n_list, nodetail(n_list), current_color, false, true) + end + setfield(n, "head", n_list) + end + cnt = cnt - 1 + elseif n_id == glyph_t then --- colorization is restricted to those fonts --- that received the “color” property upon --- loading (see ``setcolor()`` above) - if tfmdata and tfmdata.properties and tfmdata.properties.color then - local font_color = tfmdata.properties.color --- luaotfload.info( --- "n: %d; %s; %d %s, %s", --- cnt, utf.char(n.char), n.font, "<TRUE>", font_color) - if font_color ~= current_color then - local pushcolor = hex_to_rgba(font_color) - local push = newnode(whatsit_t, 8) - push.mode = 1 - push.data = pushcolor - head = insert_node_before(head, n, push) - current_color = font_color + local font_color = get_font_color(getfont(n)) + if font_color ~= current_color then + if current_color then + head, n, current_color = color_whatsit(head, n, current_color, false) end - local next_color_in = lookup_next_color (nextnode) or next_color - if next_color_in ~= font_color then - local _, popcolor = hex_to_rgba(font_color) - local pop = newnode(whatsit_t, 8) - pop.mode = 1 - pop.data = popcolor - head = insert_node_after(head, n, pop) - current_color = nil + if font_color then + head, n, current_color = color_whatsit(head, n, font_color, true) end + end --- else --- luaotfload.info( --- "n: %d; %s; %d %s", --- cnt, utf.char(n.char), n.font, "<FALSE>") + if current_color and color_callback == "pre_linebreak_filter" then + local nn = getnext(n) + while nn and getid(nn) == glyph_t do + local font_color = get_font_color(getfont(nn)) + if font_color == current_color then + n = nn + else + break + end + nn = getnext(nn) + end + if getid(nn) == disc_t then + head, n, current_color = color_whatsit(head, nn, current_color, false, true) + else + head, n, current_color = color_whatsit(head, n, current_color, false, true) + end end + + elseif n_id == whatsit_t then + if current_color then + head, n, current_color = color_whatsit(head, n, current_color, false) + end + end + + n = getnext(n) end + + if cnt == 0 and current_color then + head, _, current_color = color_whatsit(head, nodetail(head), current_color, false, true) + end + + setattribute(head, color_attr, 1) return head, current_color end --- node -> node local color_handler = function (head) - local new_head = node_colorize(head, nil, nil) + head = todirect(head) + head = node_colorize(head) + head = tonode(head) + -- now append our page resources if res then res["1"] = true local tpr = texget("pdfpageresources") + local pgf_loaded = tpr:find("/ExtGState %d+ 0 R") + if pgf_loaded then + tpr = texgettoks("pgf@sys@pgf@resource@list@extgs@toks") -- see luaotfload.sty + end + local t = "" for k in pairs(res) do - local str = stringformat("/TransGs%s<</ca %s/CA %s>>", k, k, k) - if not stringfind(tpr,str) then + local str = stringformat("/TransGs%s<</ca %s>>", k, k) -- don't touch stroking elements + if not tpr:find(str) then t = t .. str end end - print"" if t ~= "" then - print(">>", tpr, "<<") - if not stringfind(tpr,"/ExtGState<<.*>>") then - tpr = tpr.."/ExtGState<<>>" + if pgf_loaded then + texsettoks("global", "pgf@sys@pgf@resource@list@extgs@toks", tpr..t) + else + if not tpr:find("/ExtGState<<.*>>") then + tpr = tpr .. "/ExtGState<<>>" + end + tpr = tpr:gsub("/ExtGState<<", "%1"..t) + texset("global", "pdfpageresources", tpr) end - tpr = stringgsub(tpr,"/ExtGState<<","%1"..t) - texset("global", "pdfpageresources", tpr) - print(">>", tpr, "<<") end res = nil -- reset res end - return new_head + return head end local color_callback_activated = 0 --- unit -> unit add_color_callback = function ( ) - local color_callback = config.luaotfload.run.color_callback + color_callback = config.luaotfload.run.color_callback if not color_callback then - color_callback = "pre_linebreak_filter" + color_callback = "post_linebreak_filter" end if color_callback_activated == 0 then luatexbase.add_to_callback(color_callback, color_handler, "luaotfload.color_handler") + luatexbase.add_to_callback("hpack_filter", + function (head, groupcode) + if groupcode == "hbox" or + groupcode == "adjusted_hbox" or + groupcode == "align_set" then + head = color_handler(head) + end + return head + end, + "luaotfload.color_handler") color_callback_activated = 1 end end diff --git a/src/luaotfload-configuration.lua b/src/luaotfload-configuration.lua index 7791503..e907947 100644 --- a/src/luaotfload-configuration.lua +++ b/src/luaotfload-configuration.lua @@ -180,7 +180,7 @@ local default_config = { resolver = "cached", definer = "patch", log_level = 0, - color_callback = "pre_linebreak_filter", + color_callback = "post_linebreak_filter", live = true, }, misc = { diff --git a/src/luaotfload.sty b/src/luaotfload.sty index 100fb72..6ea4c0a 100644 --- a/src/luaotfload.sty +++ b/src/luaotfload.sty @@ -33,7 +33,7 @@ \csname ifluaotfloadloaded\endcsname \let\ifluaotfloadloaded\endinput \bgroup\expandafter\expandafter\expandafter\egroup -\expandafter\ifx\csname ProvidesPackage\endcsname\relax +\expandafter\ifx\csname selectfont\endcsname\relax \input luatexbase.sty \else \NeedsTeXFormat{LaTeX2e} @@ -45,3 +45,21 @@ \fi \RequireLuaModule{luaotfload-main} +% for compatibility with beamer class, which loads pgf package. +\ifcsname selectfont\endcsname + \AtBeginDocument{\@ifpackageloaded{pgfsys}{ + \csname newtoks\endcsname\pgf@sys@pgf@resource@list@extgs@toks + \def\pgf@sys@pgf@resource@list@extgs{\the\pgf@sys@pgf@resource@list@extgs@toks} + \def\pgf@sys@addpdfresource@extgs@plain#1{\global\pgf@sys@pgf@resource@list@extgs@toks + \expandafter{\the\pgf@sys@pgf@resource@list@extgs@toks #1}} + }{}} +\endinput\fi +% under plain tex, tikz (pgf) should be loaded before luaotfload. +\ifcsname pgf@sys@pgf@resource@list@extgs\endcsname\else\endinput\fi +\count255=\the\catcode`@\relax +\catcode`@=11\relax +\newtoks\pgf@sys@pgf@resource@list@extgs@toks +\def\pgf@sys@pgf@resource@list@extgs{\the\pgf@sys@pgf@resource@list@extgs@toks} +\def\pgf@sys@addpdfresource@extgs@plain#1{\global\pgf@sys@pgf@resource@list@extgs@toks + \expandafter{\the\pgf@sys@pgf@resource@list@extgs@toks #1}} +\catcode`@=\the\count255\relax |