OSDN Git Service

Fix a crash by "\ruby{Weierstraß}{ワイエルシュトラス}"
[luatex-ja/luatexja.git] / src / ltj-adjust.lua
index 81a9ea8..8579d5c 100644 (file)
@@ -1,10 +1,12 @@
 --
 -- ltj-adjust.lua
 --
+luatexja.load_module('base');      local ltjb = luatexja.base
 luatexja.load_module('jfont');     local ltjf = luatexja.jfont
 luatexja.load_module('jfmglue');   local ltjj = luatexja.jfmglue
 luatexja.load_module('stack');     local ltjs = luatexja.stack
 luatexja.load_module('direction'); local ltjd = luatexja.direction
+luatexja.load_module('lineskip');  local ltjl = luatexja.lineskip
 luatexja.adjust = luatexja.adjust or {}
 
 local to_node = node.direct.tonode
@@ -67,7 +69,11 @@ do
    local function cmp(a,b) return a[1]>b[1] end -- 大きいほうが先!
    local function make_priority_table(glue_sign)
       for i,_ in pairs(tmp) do tmp[i]=nil end
-      for i=-2,2 do tmp[#tmp+1] = { i, FROM_JFM+i } end
+      if glue_sign==2 then -- shrink
+        for i=0,63 do tmp[#tmp+1] = { (i%8)-4, FROM_JFM+i } end
+      else -- stretch
+        for i=0,63 do tmp[#tmp+1] = { math.floor(i/8)-4, FROM_JFM+i } end
+      end    
       local pt = priority_table[glue_sign]
       tmp[#tmp+1] = { pt[2]/10, XKANJI_SKIP }
       tmp[#tmp+1] = { pt[2]/10, XKANJI_SKIP_JFM }
@@ -397,10 +403,11 @@ do
       return to_node(head)
    end
    local is_reg = false
-   function enable_cb(status_le, status_pr)
+   function enable_cb(status_le, status_pr, status_lp, status_ls)
       if (status_le>0 or status_pr>0) and (not is_reg) then
-        luatexbase.add_to_callback('post_linebreak_filter',
-                                   adjust_width, 'Adjust width', 100)
+        ltjb.add_to_callback('post_linebreak_filter',
+            adjust_width, 'Adjust width', 
+           luatexbase.priority_in_callback('post_linebreak_filter', 'ltj.lineskip')-1)
         is_reg = true
       elseif is_reg and (status_le==0 and status_pr==0) then
         luatexbase.remove_from_callback('post_linebreak_filter', 'Adjust width')
@@ -408,7 +415,7 @@ do
       end
       if status_le==2 then
         if not luatexbase.in_callback('luatexja.adjust_jfmglue', 'luatexja.adjust') then
-           luatexbase.add_to_callback('luatexja.adjust_jfmglue', insert_lineend_kern, 'luatexja.adjust')
+           ltjb.add_to_callback('luatexja.adjust_jfmglue', insert_lineend_kern, 'luatexja.adjust')
         end
          myaw_step1, myaw_step1_last = dummy, aw_step1_last
       else
@@ -422,9 +429,13 @@ do
          end
       end
       myaw_step2 = (status_pr>0) and aw_step2 or aw_step2_dummy
+      luatexja.lineskip.setting(
+         status_lp>0 and 'profile' or 'dummy',
+        status_ls>0 and 'step' or 'dummy'
+      )      
    end
    function disable_cb() -- only for compatibility
-       enable_cs(0)
+       enable_cs(0,0,0,0)
    end
    luatexja.adjust.enable_cb=enable_cb
    luatexja.adjust.disable_cb=disable_cb
@@ -433,3 +444,100 @@ end
 luatexja.unary_pars.adjust = function(t)
    return is_reg and 1 or 0
 end
+
+-- ----------------------------------
+do
+  local max, ins, sort = math.max, table.insert, table.sort
+  local function insert(package, ind, d, b, e)
+    local bound = package[2]
+    bound[b], bound[e]=true, true
+    ins(package[1], {b,e,[ind]=d})
+  end
+  local function flatten(package)
+    local bd={} for i,_ in pairs(package[2]) do ins(bd,{i}) end
+    sort(bd, function (a,b) return a[1]<b[1] end)
+    local bdc=#bd; local t = package[1]
+    sort(t, function (a,b) return a[1]<b[1] end)
+    local bdi =1
+    for i=1,#t do
+      while bd[bdi][1]<t[i][1] do bdi=bdi+1 end
+      local j = bdi
+      while j<bdc and bd[j+1][1]<=t[i][2] do
+        for k,w in pairs(t[i]) do
+          if k>=3 then
+            bd[j][k]=bd[j][k] and max(bd[j][k],w) or w
+          end
+        end
+        j=j+1
+      end
+    end
+    package[2]=nil; package[1]=nil; package.flatten, package.insert=nil, nil
+    bd[#bd]=nil
+    return bd
+  end
+  function init_range()
+    return {{},{}, insert=insert, flatten=flatten}
+  end
+end
+
+-- -----------------------------------
+luatexja.adjust.step_factor = 0.5
+do
+  local insert = table.insert
+  local rangedimensions, max = node.direct.rangedimensions, math.max
+  local function profile_inner(box, range, ind, vmirrored, adj)
+    local w_acc, d_before = getfield(box,'shift'), 0
+    local x = getlist(box); local xn = node_next(x)
+    while x do
+      local w, h, d
+      if xn then w, h, d= rangedimensions(box,x,xn)
+      else w, h, d= rangedimensions(box,x) end
+      if vmirrored then h=d end
+      local w_new = w_acc + w
+      if w>=0 then
+        range:insert(ind, h, w_acc-adj, w_new)
+      else
+        range:insert(ind, h, w_new-adj, w_acc)
+      end
+      w_acc = w_new; x = xn; if x then xn = node_next(x) end
+    end
+  end  
+  function ltjl.p_profile(before, after, mirrored, bw)
+    local range, tls = init_range(), tex.lineskip.width
+    profile_inner(before, range, 3, true,     tls)
+    profile_inner(after,  range, 4, mirrored, tls)
+    range = range:flatten()
+    do
+      local dmax, d, hmax, h, lmin = 0, 0, 0, 0, 1/0
+      for i,v in ipairs(range) do
+        d, h = (v[3] or 0), (v[4] or 0)
+        if d>dmax then dmax=d end
+        if h>hmax then hmax=h end
+        if bw-h-d<lmin then lmin=bw-h-d end
+      end
+      if lmin==1/0 then lmin = bw end
+      return lmin, 
+         bw - lmin - getfield(before, 'depth')
+             - getfield(after, mirrored and 'depth' or 'height')
+    end
+  end
+end
+
+do
+  local ltja = luatexja.adjust
+  local copy_glue = ltjl.copy_glue
+  local floor, max = math.floor, math.max
+  function ltjl.l_step(dist, g, adj, normal, bw, loc)
+    if loc=='alignment' then
+      return ltjl.l_dummy(dist, g, adj, normal, bw, loc)
+    end
+    if dist < tex.lineskiplimit then
+    local f = max(1, bw*ltja.step_factor)
+       copy_glue(g, tex.baselineskip, 1, normal - f * floor((dist-tex.lineskip.width)/f))
+    else
+       copy_glue(g, tex.baselineskip, 2, normal)
+    end
+  end
+end
+
+