texlive[61446] Master/texmf-dist: luapstricks (30dec21)

commits+karl at tug.org commits+karl at tug.org
Thu Dec 30 22:19:08 CET 2021


Revision: 61446
          http://tug.org/svn/texlive?view=revision&revision=61446
Author:   karl
Date:     2021-12-30 22:19:07 +0100 (Thu, 30 Dec 2021)
Log Message:
-----------
luapstricks (30dec21)

Modified Paths:
--------------
    trunk/Master/texmf-dist/doc/lualatex/luapstricks/README.md
    trunk/Master/texmf-dist/tex/lualatex/luapstricks/luapstricks.lua

Modified: trunk/Master/texmf-dist/doc/lualatex/luapstricks/README.md
===================================================================
--- trunk/Master/texmf-dist/doc/lualatex/luapstricks/README.md	2021-12-30 21:18:55 UTC (rev 61445)
+++ trunk/Master/texmf-dist/doc/lualatex/luapstricks/README.md	2021-12-30 21:19:07 UTC (rev 61446)
@@ -8,7 +8,7 @@
   1. Make sure that you have the latest pstricks version installed.
   2. Run `l3build install` *or* copy `luapstricks.lua` from this repository into the directory of your TeX files or another directory in your TeX search path.
   3. Compile your document with `lualatex`.
-  4. Given the current state of development of this project, the previous stage probably failed. Write a bug report to the author. Otherwise go to step 7.
+  4. Given that most people immediately stop reading after they get a result and you are still here, the previous stage probably failed. Write a bug report to the author. Otherwise go to step 7.
   5. Wait for a fix.
   6. Go back to step 2 and try again.
   7. It worked? That's great. Feel free to inform the author anyway and share the awesome images you created.

Modified: trunk/Master/texmf-dist/tex/lualatex/luapstricks/luapstricks.lua
===================================================================
--- trunk/Master/texmf-dist/tex/lualatex/luapstricks/luapstricks.lua	2021-12-30 21:18:55 UTC (rev 61445)
+++ trunk/Master/texmf-dist/tex/lualatex/luapstricks/luapstricks.lua	2021-12-30 21:19:07 UTC (rev 61446)
@@ -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 @@
 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 @@
                                                                       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 @@
   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 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 @@
         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 @@
         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,7 +1157,7 @@
         return push(height-i)
       end
     end
-    error'Unmatched mark'
+    error'unmatchedmark'
   end,
   cleartomark = function()
     local entry
@@ -1091,7 +1164,7 @@
     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 @@
           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 @@
     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 @@
     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 @@
     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 @@
       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 @@
       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 @@
   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,7 +2915,8 @@
     }
   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
@@ -2814,6 +2923,14 @@
       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 @@
     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 @@
   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 @@
           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 @@
           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 @@
   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



More information about the tex-live-commits mailing list.