summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/tex/lualatex/luapstricks
diff options
context:
space:
mode:
Diffstat (limited to 'Master/texmf-dist/tex/lualatex/luapstricks')
-rw-r--r--Master/texmf-dist/tex/lualatex/luapstricks/luapstricks.lua208
1 files changed, 187 insertions, 21 deletions
diff --git a/Master/texmf-dist/tex/lualatex/luapstricks/luapstricks.lua b/Master/texmf-dist/tex/lualatex/luapstricks/luapstricks.lua
index 7da1c9c1339..e505f5458aa 100644
--- a/Master/texmf-dist/tex/lualatex/luapstricks/luapstricks.lua
+++ b/Master/texmf-dist/tex/lualatex/luapstricks/luapstricks.lua
@@ -18,8 +18,8 @@
if luatexbase then
luatexbase.provides_module {
name = 'luapstricks',
- version = 'v0.3',
- date = '2021-11-12',
+ version = 'v0.4',
+ date = '2021-12-29',
description = 'PSTricks backend for LuaLaTeX',
}
end
@@ -502,8 +502,16 @@ end
local execute_ps, execute_tok
local dictionary_stack
+
+-- About the bbox entry:
+-- - If the bounding box is not currently tracked, it is set to nil
+-- - Otherwise it's a linked list linked with the .next field. Every entry is a "matrix level"
+-- - if .bbox[1] is nil, the current matrix level does not have a set bounding box yet
+-- - Otherside it's {min_x, min_y, max_x, max_y}
+-- - If a .bbox.matrix entry is present then it describes the matrix which should be applied before the bbox gets added to the next "matrix level"
local graphics_stack = {{
matrix = {10, 0, 0, 10, 0, 0}, -- Chosen for consistency with GhostScript's pdfwrite. Must be the same as defaultmatrix
+ bbox = nil,
linewidth = nil,
current_path = nil,
current_point = nil,
@@ -654,6 +662,12 @@ local function flush_delayed_table(delayed, state, force_start)
delayed_matrix[5], delayed_matrix[6])
if cm_string == "1.00000 0.00000 0.00000 1.00000 0.00000 0.00000 cm" then
cm_string = nil
+ else
+ local bbox = state.bbox
+ if bbox then
+ state.bbox = { matrix = delayed_matrix, next = bbox }
+ delayed.matrix = {} -- Will be initialized in reset_delayed
+ end
end
-- Before flushing, make sure that the current graphics state has started.
@@ -686,6 +700,47 @@ local function flush_delayed(force_start)
return flush_delayed_table(delayed, graphics_stack[#graphics_stack], force_start)
end
+local function register_point_bbox(bbox, x, y)
+ local min_x, min_y, max_x, max_y = bbox[1], bbox[2], bbox[3], bbox[4]
+ if min_x then
+ if x < min_x then
+ bbox[1] = x
+ elseif x > max_x then
+ bbox[3] = x
+ end
+ if y < min_y then
+ bbox[2] = y
+ elseif y > max_y then
+ bbox[4] = y
+ end
+ else
+ bbox[1], bbox[2], bbox[3], bbox[4] = x, y, x, y
+ end
+end
+
+-- Only call after flush_delayed
+local function register_point(state, x, y)
+ local bbox = state.bbox
+ if not bbox then return end
+ return register_point_bbox(bbox, x, y)
+end
+
+local function merge_bbox(bbox, after)
+ if bbox[1] then
+ local matrix = bbox.matrix
+ if matrix then
+ register_point_bbox(after, matrix_transform(bbox[1], bbox[2], matrix[1], matrix[2], matrix[3], matrix[4], matrix[5], matrix[6]))
+ register_point_bbox(after, matrix_transform(bbox[1], bbox[4], matrix[1], matrix[2], matrix[3], matrix[4], matrix[5], matrix[6]))
+ register_point_bbox(after, matrix_transform(bbox[3], bbox[2], matrix[1], matrix[2], matrix[3], matrix[4], matrix[5], matrix[6]))
+ register_point_bbox(after, matrix_transform(bbox[3], bbox[4], matrix[1], matrix[2], matrix[3], matrix[4], matrix[5], matrix[6]))
+ else
+ register_point_bbox(after, bbox[1], bbox[2])
+ register_point_bbox(after, bbox[3], bbox[4])
+ end
+ end
+ return after
+end
+
function drawarc(xc, yc, r, a1, a2)
a1, a2 = math.rad(a1), math.rad(a2)
local dx, dy = r*math.cos(a1), r*math.sin(a1)
@@ -876,6 +931,7 @@ local function generic_show(str, ax, ay)
local w = 0
if fonttype == 0x1CA then
local characters = assert(font.getfont(fid)).characters
+ local max_d, max_h = 0, 0
flush_delayed()
if pdfprint ~= gobble then
vf.push()
@@ -890,12 +946,29 @@ local function generic_show(str, ax, ay)
end
end
local char = characters[b]
- w = w + (char and char.width or 0)
+ if char then
+ w = w + (char.width or 0)
+ if char.depth and char.depth > max_d then
+ max_d = char.depth
+ end
+ if char.height and char.height > max_h then
+ max_h = char.height
+ end
+ end
end
+ w = w/65781.76
if pdfprint ~= gobble then
+ max_d = max_d/65781.76
+ max_h = max_h/65781.76
+ register_point(state, 0, -max_d)
+ if ax then
+ local count = #str
+ register_point(state, w + count * ax, max_h + count * ay)
+ else
+ register_point(state, w, max_h)
+ end
vf.pop()
end
- w = w/65781.76
elseif fonttype == 3 then
for b in string.bytes(str) do
systemdict.value.gsave()
@@ -1061,7 +1134,7 @@ systemdict = {kind = 'dict', value = {
break
end
end
- if not mark_pos then error'Unmatched mark' end
+ if not mark_pos then error'unmatchedmark' end
local dict = lua.newtable(0, (#operand_stack-mark_pos) // 2)
for i = mark_pos + 1, #operand_stack - 1, 2 do
push(operand_stack[i])
@@ -1084,14 +1157,14 @@ systemdict = {kind = 'dict', value = {
return push(height-i)
end
end
- error'Unmatched mark'
+ error'unmatchedmark'
end,
cleartomark = function()
local entry
repeat
entry = pop()
until (not entry) or type(entry) == 'table' and entry.kind == 'mark'
- if not entry then error'Unmatched mark' end
+ if not entry then error'unmatchedmark' end
end,
['if'] = function()
@@ -1316,7 +1389,11 @@ systemdict = {kind = 'dict', value = {
local after = node.direct.getnext(n)
local head = node.direct.getlist(parent)
node.direct.setnext(n, nil)
- node.direct.setlist(parent, subbox.box)
+ node.direct.setlist(parent, n)
+ local state = graphics_stack[#graphics_stack]
+ local w, h, d = node.direct.dimensions(n)
+ register_point(state, 0, -d/65781.76)
+ register_point(state, w/65781.76, h/65781.76)
vf.node(parent)
node.direct.setnext(n, after)
node.direct.setlist(parent, head)
@@ -2234,12 +2311,20 @@ systemdict = {kind = 'dict', value = {
local current_path = state.current_path
if not current_path then return end
current_path[#current_path+1] = 'f*'
+ flush_delayed()
+ local x
for i = 1, #current_path do
- if type(current_path[i]) == 'number' then
- current_path[i] = string.format('%.5f', current_path[i])
+ local value = current_path[i]
+ if type(value) == 'number' then
+ current_path[i] = string.format('%.5f', value)
+ if x then
+ register_point(state, x, value)
+ x = nil
+ else
+ x = value
+ end
end
end
- flush_delayed()
pdfprint((table.concat(current_path, ' '):gsub('%.?0+ ', ' ')))
state.current_path, state.current_point = nil
end,
@@ -2248,12 +2333,20 @@ systemdict = {kind = 'dict', value = {
local current_path = state.current_path
if not current_path then return end
current_path[#current_path+1] = 'f'
+ flush_delayed()
+ local x
for i = 1, #current_path do
- if type(current_path[i]) == 'number' then
- current_path[i] = string.format('%.5f', current_path[i])
+ local value = current_path[i]
+ if type(value) == 'number' then
+ current_path[i] = string.format('%.5f', value)
+ if x then
+ register_point(state, x, value)
+ x = nil
+ else
+ x = value
+ end
end
end
- flush_delayed()
pdfprint((table.concat(current_path, ' '):gsub('%.?0+ ', ' ')))
state.current_path, state.current_point = nil
end,
@@ -2262,12 +2355,20 @@ systemdict = {kind = 'dict', value = {
local current_path = state.current_path
if not current_path then return end
current_path[#current_path+1] = 'S'
+ flush_delayed()
+ local x
for i = 1, #current_path do
- if type(current_path[i]) == 'number' then
- current_path[i] = string.format('%.5f', current_path[i])
+ local value = current_path[i]
+ if type(value) == 'number' then
+ current_path[i] = string.format('%.5f', value)
+ if x then
+ register_point(state, x, value)
+ x = nil
+ else
+ x = value
+ end
end
end
- flush_delayed()
pdfprint((table.concat(current_path, ' '):gsub('%.?0+ ', ' ')))
state.current_path, state.current_point = nil
end,
@@ -2340,6 +2441,9 @@ systemdict = {kind = 'dict', value = {
local y = pop_num()
local x = pop_num()
pdfprint((string.format('%.5f %.5f %.5f %.5f re S', x, y, w, h):gsub('%.?0+ ', ' ')))
+ local state = graphics_stack[#graphics_stack]
+ register_point(state, x, y)
+ register_point(state, x + w, y + h)
else
error'Unsupported rectstroke variant'
end
@@ -2356,6 +2460,9 @@ systemdict = {kind = 'dict', value = {
local y = pop_num()
local x = pop_num()
pdfprint((string.format('%.5f %.5f %.5f %.5f re f', x, y, w, h):gsub('%.?0+ ', ' ')))
+ local state = graphics_stack[#graphics_stack]
+ register_point(state, x, y)
+ register_point(state, x + w, y + h)
else
error'Unsupported rectfill variant'
end
@@ -2799,7 +2906,8 @@ systemdict = {kind = 'dict', value = {
end,
gsave = function()
- graphics_stack[#graphics_stack+1] = table.copy(graphics_stack[#graphics_stack])
+ local bbox = graphics_stack[#graphics_stack].bbox
+ graphics_stack[#graphics_stack+1] = table.copy(graphics_stack[#graphics_stack], bbox and {[bbox] = {}})
graphics_stack[#graphics_stack].saved_delayed = delayed
delayed = {
text = {},
@@ -2807,13 +2915,22 @@ systemdict = {kind = 'dict', value = {
}
end,
grestore = function()
- local saved_delayed = graphics_stack[#graphics_stack].saved_delayed
+ local state = graphics_stack[#graphics_stack]
+ local saved_delayed = state.saved_delayed
if saved_delayed then
delayed = saved_delayed
else
pdfprint'Q'
reset_delayed(delayed)
end
+ local upper_state = graphics_stack[#graphics_stack-1]
+ local upper_bbox = upper_state.bbox
+ if upper_bbox then
+ local bbox = assert(state.bbox)
+ while upper_bbox ~= bbox do
+ bbox = merge_bbox(bbox, bbox.next or upper_bbox)
+ end
+ end
graphics_stack[#graphics_stack] = nil
end,
@@ -3364,6 +3481,33 @@ systemdict = {kind = 'dict', value = {
end
end,
+ ['.trackbbox'] = function()
+ local state = graphics_stack[#graphics_stack]
+ flush_delayed()
+ state.bbox = { next = state.bbox, start = true }
+ end,
+ -- Trackedbbox should only be invoked if the current matrix is essentially the same
+ -- as in the corresponding .trackbbox, otherwise everything gets messed up.
+ -- This isn't checked, mostly because we don't want a check to be too sensitive.
+ ['.trackedbbox'] = function()
+ local state = graphics_stack[#graphics_stack]
+ local bbox = state.bbox
+ if not bbox then
+ error'trackedbbox without matching trackbbox'
+ end
+ while not bbox.start do
+ if not bbox.next then
+ error'Illegal nesting of trackbbox/trackedbbox and gsave/grestore'
+ end
+ bbox = merge_bbox(bbox, bbox.next)
+ end
+ state.bbox = bbox.next and merge_bbox(bbox, bbox.next)
+ push(bbox[1] or 0)
+ push(bbox[2] or 0)
+ push(bbox[3] or 0)
+ push(bbox[4] or 0)
+ end,
+
revision = 1000,
['true'] = true,
['false'] = false,
@@ -3726,7 +3870,16 @@ local register_texbox do
function register_texbox(box)
id = id + 1
box = setmetatable({box = node.direct.todirect(box)}, meta)
- local op = function() flush_delayed() vf.push() vf.node(box.box) vf.pop() end
+ local op = function()
+ flush_delayed()
+ local state = graphics_stack[#graphics_stack]
+ local w, h, d = node.direct.dimensions(box.box)
+ register_point(state, 0, -d/65781.76)
+ register_point(state, w/65781.76, h/65781.76)
+ vf.push()
+ vf.node(box.box)
+ vf.pop()
+ end
lua_node_lookup[op] = box
dict[id] = op
return id
@@ -3898,9 +4051,11 @@ local fid = font.define{
TeXDict.ocount = height
operand_stack[height + 1], operand_stack[height + 2] = ps_pos_x/65781.76, ps_pos_y/65781.76
ps_pos_x, ps_pos_y = nil
+ local graphics_height
if direct then
systemdict.value.moveto()
else
+ graphics_height = #graphics_stack
systemdict.value.gsave()
systemdict.value.translate()
end
@@ -3917,6 +4072,16 @@ local fid = font.define{
flush_delayed()
if not direct then
systemdict.value.grestore()
+ if graphics_height ~= #graphics_stack then
+ if graphics_height < #graphics_stack then
+ texio.write_nl"luapstricks: PS block contains unbalanced gsave. grestore will be executed to compensate."
+ repeat
+ systemdict.value.grestore()
+ until graphics_height == #graphics_stack
+ else
+ texio.write_nl"luapstricks: PS block contains unbalanced grestore."
+ end
+ end
height = TeXDict.ocount or height
local new_height = #operand_stack
assert(new_height >= height)
@@ -3977,7 +4142,8 @@ do
local ps_rgb = 'rgb ' * l.C(l.P(1)^0) * l.Cc' setrgbcolor' * l.Cc'rgb '
local ps_cmyk = 'cmyk ' * l.C(l.P(1)^0) * l.Cc' setcmykcolor' * l.Cc'cmyk '
local ps_gray = 'gray ' * l.C(l.P(1)^0) * l.Cc' setgray' * l.Cc'gray '
- local pscolor = ps_rgb + ps_gray + ps_gray
+ local ps_hsb = 'hsb ' * l.C(l.P(1)^0) * l.Cc' sethsbcolor' * l.Cc'hsb '
+ local pscolor = ps_rgb + ps_gray + ps_gray + ps_hsb
local pdf_rgb = l.Cmt(l.C(number * whitespace * number * whitespace * number / 0) * whitespace * 'rg'
* whitespace * l.C(number * whitespace * number * whitespace * number / 0) * whitespace * 'RG' * -1, function(s, p, a, b)
if a == b then