summaryrefslogtreecommitdiff
path: root/tex/context/base/font-mps.lua
diff options
context:
space:
mode:
Diffstat (limited to 'tex/context/base/font-mps.lua')
-rw-r--r--tex/context/base/font-mps.lua379
1 files changed, 379 insertions, 0 deletions
diff --git a/tex/context/base/font-mps.lua b/tex/context/base/font-mps.lua
new file mode 100644
index 000000000..1465b475b
--- /dev/null
+++ b/tex/context/base/font-mps.lua
@@ -0,0 +1,379 @@
+if not modules then modules = { } end modules ['font-mps'] = {
+ version = 1.001,
+ comment = "companion to font-ini.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local concat = table.concat
+local formatters = string.formatters
+
+-- QP0 [QP1] QP2 => CP0 [CP1 CP2] CP3
+
+-- CP0 = QP0
+-- CP3 = QP2
+--
+-- CP1 = QP0 + 2/3 *(QP1-QP0)
+-- CP2 = QP2 + 2/3 *(QP1-QP2)
+
+fonts = fonts or { }
+local metapost = fonts.metapost or { }
+fonts.metapost = metapost
+
+local f_moveto = formatters["(%.4G,%.4G)"]
+local f_lineto = formatters["--(%.4G,%.4G)"]
+local f_curveto = formatters["..controls(%.4G,%.4G)and(%.4G,%.4G)..(%.4G,%.4G)"]
+local s_cycle = "--cycle"
+
+local f_nofill = formatters["nofill %s;"]
+local f_dofill = formatters["fill %s;"]
+
+local f_draw_trace = formatters["drawpathonly %s;"]
+local f_draw = formatters["draw %s;"]
+
+local f_boundingbox = formatters["((%.4G,%.4G)--(%.4G,%.4G)--(%.4G,%.4G)--(%.4G,%.4G)--cycle)"]
+local f_vertical = formatters["((%.4G,%.4G)--(%.4G,%.4G))"]
+
+function metapost.boundingbox(d,factor)
+ local bounds = d.boundingbox
+ local factor = factor or 1
+ local llx = factor*bounds[1]
+ local lly = factor*bounds[2]
+ local urx = factor*bounds[3]
+ local ury = factor*bounds[4]
+ return f_boundingbox(llx,lly,urx,lly,urx,ury,llx,ury)
+end
+
+function metapost.widthline(d,factor)
+ local bounds = d.boundingbox
+ local factor = factor or 1
+ local lly = factor*bounds[2]
+ local ury = factor*bounds[4]
+ local width = factor*d.width
+ return f_vertical(width,lly,width,ury)
+end
+
+function metapost.zeroline(d,factor)
+ local bounds = d.boundingbox
+ local factor = factor or 1
+ local lly = factor*bounds[2]
+ local ury = factor*bounds[4]
+ return f_vertical(0,lly,0,ury)
+end
+
+function metapost.paths(d,factor)
+ local sequence = d.sequence
+ local segments = d.segments
+ local list = { }
+ local path = { } -- recycled
+ local size = 0
+ local factor = factor or 1
+ if sequence then
+ local i = 1
+ local n = #sequence
+ while i < n do
+ local operator = sequence[i]
+ if operator == "m" then -- "moveto"
+ if size > 0 then
+ size = size + 1
+ path[size] = s_cycle
+ list[#list+1] = concat(path,"",1,size)
+ size = 1
+ else
+ size = size + 1
+ end
+ path[size] = f_moveto(factor*sequence[i+1],factor*sequence[i+2])
+ i = i + 3
+ elseif operator == "l" then -- "lineto"
+ size = size + 1
+ path[size] = f_lineto(factor*sequence[i+1],factor*sequence[i+2])
+ i = i + 3
+ elseif operator == "c" then -- "curveto"
+ size = size + 1
+ path[size] = f_curveto(factor*sequence[i+1],factor*sequence[i+2],factor*sequence[i+3],factor*sequence[i+4],factor*sequence[i+5],factor*sequence[i+6])
+ i = i + 7
+ elseif operator =="q" then -- "quadraticto"
+ size = size + 1
+ -- first is always a moveto
+ local l_x, l_y = factor*sequence[i-2], factor*sequence[i-1]
+ local m_x, m_y = factor*sequence[i+1], factor*sequence[i+2]
+ local r_x, r_y = factor*sequence[i+3], factor*sequence[i+4]
+ path[size] = f_curveto (
+ l_x + 2/3 * (m_x-l_x),
+ l_y + 2/3 * (m_y-l_y),
+ r_x + 2/3 * (m_x-r_x),
+ r_y + 2/3 * (m_y-r_y),
+ r_x, r_y
+ )
+ i = i + 5
+ else
+ -- weird
+ i = i + 1
+ end
+ end
+ elseif segments then
+ for i=1,#segments do
+ local segment = segments[i]
+ local operator = segment[#segment]
+ if operator == "m" then -- "moveto"
+ if size > 0 then
+ size = size + 1
+ path[size] = s_cycle
+ list[#list+1] = concat(path,"",1,size)
+ size = 1
+ else
+ size = size + 1
+ end
+ path[size] = f_moveto(factor*segment[1],factor*segment[2])
+ elseif operator == "l" then -- "lineto"
+ size = size + 1
+ path[size] = f_lineto(factor*segment[1],factor*segment[2])
+ elseif operator == "c" then -- "curveto"
+ size = size + 1
+ path[size] = f_curveto(factor*segment[1],factor*segment[2],factor*segment[3],factor*segment[4],factor*segment[5],factor*segment[6])
+ elseif operator =="q" then -- "quadraticto"
+ size = size + 1
+ -- first is always a moveto
+ local prev = segments[i-1]
+ local l_x, l_y = factor*prev[#prev-2], factor*prev[#prev-1]
+ local m_x, m_y = factor*segment[1], factor*segment[2]
+ local r_x, r_y = factor*segment[3], factor*segment[4]
+ path[size] = f_curveto (
+ l_x + 2/3 * (m_x-l_x),
+ l_y + 2/3 * (m_y-l_y),
+ r_x + 2/3 * (m_x-r_x),
+ r_y + 2/3 * (m_y-r_y),
+ r_x, r_y
+ )
+ else
+ -- weird
+ end
+ end
+ else
+ return
+ end
+ if size > 0 then
+ size = size + 1
+ path[size] = s_cycle
+ list[#list+1] = concat(path,"",1,size)
+ end
+ return list
+end
+
+function metapost.fill(paths)
+ local r = { }
+ local n = #paths
+ for i=1,n do
+ if i < n then
+ r[i] = f_nofill(paths[i])
+ else
+ r[i] = f_dofill(paths[i])
+ end
+ end
+ return concat(r)
+end
+
+function metapost.draw(paths,trace)
+ local r = { }
+ local n = #paths
+ for i=1,n do
+ if trace then
+ r[i] = f_draw_trace(paths[i])
+ else
+ r[i] = f_draw(paths[i])
+ end
+ end
+ return concat(r)
+end
+
+function metapost.maxbounds(data,index,factor)
+ local maxbounds = data.maxbounds
+ local factor = factor or 1
+ local glyphs = data.glyphs
+ local glyph = glyphs[index]
+ local boundingbox = glyph.boundingbox
+ local xmin, ymin, xmax, ymax
+ if not maxbounds then
+ xmin, ymin, xmax, ymax = 0, 0, 0, 0
+ for i=1,#glyphs do
+ local d = glyphs[i]
+ if d then
+ local b = d.boundingbox
+ if b then
+ if b[1] < xmin then xmin = b[1] end
+ if b[2] < ymin then ymin = b[2] end
+ if b[3] > xmax then xmax = b[3] end
+ if b[4] > ymax then ymax = b[4] end
+ end
+ end
+ end
+ maxbounds = { xmin, ymin, xmax, ymax }
+ data.maxbounds = maxbounds
+ else
+ xmin = maxbounds[1]
+ ymin = maxbounds[2]
+ xmax = maxbounds[3]
+ ymax = maxbounds[4]
+ end
+ local llx = boundingbox[1]
+ local lly = boundingbox[2]
+ local urx = boundingbox[3]
+ local ury = boundingbox[4]
+ local width = glyph.width
+ if llx > 0 then
+ llx = 0
+ end
+ if width > urx then
+ urx = width
+ end
+ return f_boundingbox(
+ factor*llx,factor*ymin,
+ factor*urx,factor*ymin,
+ factor*urx,factor*ymax,
+ factor*llx,factor*ymax
+ )
+end
+
+----- formatters = string.formatters
+----- concat = table.concat
+
+local nodecodes = nodes.nodecodes -- no nuts yet
+
+local glyph_code = nodecodes.glyph
+local disc_code = nodecodes.disc
+local kern_code = nodecodes.kern
+local glue_code = nodecodes.glue
+local hlist_code = nodecodes.hlist
+local vlist_code = nodecodes.vlist
+local penalty_code = nodecodes.penalty
+
+----- metapost = fonts.glyphs.metapost
+
+local characters = fonts.hashes.characters
+local shapes = fonts.hashes.shapes
+local topaths = fonts.metapost.paths
+
+local f_code = formatters["mfun_do_outline_text_flush(%q,%i,%.4G,%.4G)(%,t);"]
+local s_nothing = "(origin scaled 10)"
+
+local sc = 10
+local fc = number.dimenfactors.bp * sc / 10
+
+-- todo: make the next more efficient:
+
+function metapost.output(kind,font,char,advance,shift)
+ local character = characters[font][char]
+ if char then
+ local index = character.index
+ if index then
+ local shapedata = shapes[font]
+ local glyphs = shapedata.glyphs -- todo: subfonts fonts.shapes.indexed(font,sub)
+ if glyphs then
+ local glyf = data.glyphs[index]
+ if glyf then
+ local units = data.fontheader and data.fontheader.units or data.units or 1000
+ local factor = sc/units
+ local shift = shift or 0
+ local advance = advance or 0
+ local paths = topaths(glyf,factor)
+ local code = f_code(kind,#paths,advance,shift,paths)
+ return code, glyf.width * factor
+ end
+ end
+ end
+ end
+ return s_nothing, 10 * sc/1000
+end
+
+-- shifted hboxes
+
+function fonts.metapost.boxtomp(n,kind)
+
+ local result = { }
+ local advance = 0
+ local distance = 0
+
+ local boxtomp
+
+ local function horizontal(current,shift,glue_sign,glue_set,glue_order)
+ while current do
+ local id = current.id
+ if id == glyph_code then
+ local code, width = metapost.output(kind,current.font,current.char,advance,-(shift or 0)* fc)
+ result[#result+1] = code
+ advance = advance + width
+ elseif id == disc_code then
+ local replace = current.replace
+ if replace then
+ horizontal(replace,shift,glue_sign,glue_set,glue_order)
+ end
+ elseif id == kern_code then
+ advance = advance + current.kern * fc
+ elseif id == glue_code then
+ local spec = current.spec
+ local width = spec.width
+ if glue_sign == 1 then
+ if spec.stretch_order == glue_order then
+ advance = advance + (width + spec.stretch * glue_set) * fc
+ else
+ advance = advance + width * fc
+ end
+ elseif glue_sign == 2 then
+ if spec.shrink_order == glue_order then
+ advance = advance + (width - spec.shrink * glue_set) * fc
+ else
+ advance = advance + width * fc
+ end
+ else
+ advance = advance + width * fc
+ end
+ elseif id == hlist_code then
+ local a = advance
+ boxtomp(current,(shift or 0)+current.shift,current.glue_sign,current.glue_set,current.glue_order)
+ advance = a + current.width * fc
+ elseif id == vlist_code then
+ boxtomp(current) -- ,distance + (shift or 0),current.glue_set*current.glue_sign)
+ else -- todo: rule
+ -- print("horizontal >>>",nodecodes[id])
+ end
+ current = current.next
+ end
+ end
+
+ local function vertical(current,shift)
+ while current do
+ local id = current.id
+ if id == hlist_code then
+ distance = distance + current.height
+ boxtomp(current,distance + (shift or 0),current.glue_set*current.glue_sign)
+ distance = distance + current.depth
+ elseif id == vlist_code then
+ print("vertical >>>",nodecodes[id])
+ elseif id == kern_code then
+ distance = distance + current.kern
+ advance = 0
+ elseif id == glue_code then
+ distance = distance + current.spec.width
+ advance = 0
+ end
+ current = current.next
+ end
+ end
+
+ boxtomp = function(list,shift)
+ local current = list.list
+ if current then
+ if list.id == hlist_code then
+ horizontal(current,shift,list.glue_sign,list.glue_set,list.glue_order)
+ else
+ vertical(current,shift)
+ end
+ end
+ end
+
+ local box = tex.box[n]
+ boxtomp(box,box.shift,box.glue_sign,box.glue_set,box.glue_order)
+ return concat(result)
+
+end