• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

sile-typesetter / sile / 6713098919

31 Oct 2023 10:21PM UTC coverage: 52.831% (-21.8%) from 74.636%
6713098919

push

github

web-flow
Merge d0a2a1ee9 into b185d4972

45 of 45 new or added lines in 3 files covered. (100.0%)

8173 of 15470 relevant lines covered (52.83%)

6562.28 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

50.97
/outputters/libtexpdf.lua
1
local base = require("outputters.base")
7✔
2
local pdf = require("justenoughlibtexpdf")
7✔
3

4
local cursorX = 0
7✔
5
local cursorY = 0
7✔
6

7
local started = false
7✔
8
local lastkey = false
7✔
9

10
local debugfont = SILE.font.loadDefaults({ family = "Gentium Plus", language = "en", size = 10 })
7✔
11

12
local glyph2string = function (glyph)
13
  return string.char(math.floor(glyph % 2^32 / 2^8)) .. string.char(glyph % 0x100)
4,575✔
14
end
15

16
local _dl = 0.5
7✔
17

18
local _debugfont
19
local _font
20

21
local outputter = pl.class(base)
7✔
22
outputter._name = "libtexpdf"
7✔
23
outputter.extension = "pdf"
7✔
24

25
-- The outputter init can't actually initialize output (as logical as it might
26
-- have seemed) because that requires a page size which we don't know yet.
27
-- function outputter:_init () end
28

29
function outputter:_ensureInit ()
7✔
30
  if not started then
1,083✔
31
    local w, h = SILE.documentState.paperSize[1], SILE.documentState.paperSize[2]
7✔
32
    local fname = self:getOutputFilename()
7✔
33
    pdf.init(fname == "-" and "/dev/stdout" or fname, w, h, SILE.full_version)
7✔
34
    pdf.beginpage()
7✔
35
    started = true
7✔
36
  end
37
end
38

39
function outputter:newPage ()
7✔
40
  self:_ensureInit()
×
41
  pdf.endpage()
×
42
  pdf.beginpage()
×
43
end
44

45
-- pdf structure package needs a tie in here
46
function outputter._endHook (_)
7✔
47
end
48

49
function outputter:finish ()
7✔
50
  self:_ensureInit()
7✔
51
  pdf.endpage()
7✔
52
  self:_endHook()
7✔
53
  pdf.finish()
7✔
54
  started = false
7✔
55
  lastkey = nil
7✔
56
end
57

58
function outputter.getCursor (_)
7✔
59
  return cursorX, cursorY
804✔
60
end
61

62
function outputter.setCursor (_, x, y, relative)
7✔
63
  x = SU.cast("number", x)
1,796✔
64
  y = SU.cast("number", y)
1,796✔
65
  local offset = relative and { x = cursorX, y = cursorY } or { x = 0, y = 0 }
898✔
66
  cursorX = offset.x + x
898✔
67
  cursorY = offset.y + (relative and 0 or SILE.documentState.paperSize[2]) - y
898✔
68
end
69

70
function outputter:setColor (color)
7✔
71
  self:_ensureInit()
×
72
  if color.r then pdf.setcolor_rgb(color.r, color.g, color.b) end
×
73
  if color.c then pdf.setcolor_cmyk(color.c, color.m, color.y, color.k) end
×
74
  if color.l then pdf.setcolor_gray(color.l) end
×
75
end
76

77
function outputter:pushColor (color)
7✔
78
  self:_ensureInit()
×
79
  if color.r then pdf.colorpush_rgb(color.r, color.g, color.b) end
×
80
  if color.c then pdf.colorpush_cmyk(color.c, color.m, color.y, color.k) end
×
81
  if color.l then pdf.colorpush_gray(color.l) end
×
82
end
83

84
function outputter:popColor ()
7✔
85
  self:_ensureInit()
×
86
  pdf.colorpop()
×
87
end
88

89
function outputter:_drawString (str, width, x_offset, y_offset)
7✔
90
  local x, y = self:getCursor()
804✔
91
  pdf.colorpush_rgb(0,0,0)
804✔
92
  pdf.colorpop()
804✔
93
  pdf.setstring(x+x_offset, y+y_offset, str, string.len(str), _font, width)
1,608✔
94
end
95

96
function outputter:drawHbox (value, width)
7✔
97
  width = SU.cast("number", width)
1,076✔
98
  self:_ensureInit()
538✔
99
  if not value.glyphString then return end
538✔
100
  -- Nodes which require kerning or have offsets to the glyph
101
  -- position should be output a glyph at a time. We pass the
102
  -- glyph advance from the htmx table, so that libtexpdf knows
103
  -- how wide each glyph is. It uses this to then compute the
104
  -- relative position between the pen after the glyph has been
105
  -- painted (cursorX + glyphAdvance) and the next painting
106
  -- position (cursorX + width - remember that the box's "width"
107
  -- is actually the shaped x_advance).
108
  if value.complex then
538✔
109
    for i = 1, #value.items do
454✔
110
      local item = value.items[i]
360✔
111
      local buf = glyph2string(item.gid)
360✔
112
      self:_drawString(buf, item.glyphAdvance, item.x_offset or 0, item.y_offset or 0)
360✔
113
      self:setCursor(item.width, 0, true)
360✔
114
    end
115
  else
116
    local buf = {}
444✔
117
    for i = 1, #value.glyphString do
1,609✔
118
      buf[i] = glyph2string(value.glyphString[i])
2,330✔
119
    end
120
    buf = table.concat(buf, "")
444✔
121
    self:_drawString(buf, width, 0, 0)
444✔
122
  end
123
end
124

125
function outputter:_withDebugFont (callback)
7✔
126
  if not _debugfont then
×
127
    _debugfont = self:setFont(debugfont)
×
128
  end
129
  local oldfont = _font
×
130
  _font = _debugfont
×
131
  callback()
×
132
  _font = oldfont
×
133
end
134

135
function outputter:setFont (options)
7✔
136
  self:_ensureInit()
538✔
137
  local key = SILE.font._key(options)
538✔
138
  if lastkey and key == lastkey then return _font end
538✔
139
  local font = SILE.font.cache(options, SILE.shaper.getFace)
114✔
140
  if options.direction == "TTB" then
114✔
141
    font.layout_dir = 1
×
142
  end
143
  if SILE.typesetter.frame and SILE.typesetter.frame:writingDirection() == "TTB" then
228✔
144
    pdf.setdirmode(1)
×
145
  else
146
    pdf.setdirmode(0)
114✔
147
  end
148
  _font = pdf.loadfont(font)
114✔
149
  if _font < 0 then SU.error("Font loading error for " .. pl.pretty.write(options, "")) end
114✔
150
  lastkey = key
114✔
151
  return _font
114✔
152
end
153

154
function outputter:drawImage (src, x, y, width, height, pageno)
7✔
155
  x = SU.cast("number", x)
×
156
  y = SU.cast("number", y)
×
157
  width = SU.cast("number", width)
×
158
  height = SU.cast("number", height)
×
159
  self:_ensureInit()
×
160
  pdf.drawimage(src, x, y, width, height, pageno or 1)
×
161
end
162

163
function outputter:getImageSize (src, pageno)
7✔
164
  self:_ensureInit() -- in case it's a PDF file
×
165
  local llx, lly, urx, ury, xresol, yresol = pdf.imagebbox(src, pageno or 1)
×
166
  return (urx-llx), (ury-lly), xresol, yresol
×
167
end
168

169
function outputter:drawSVG (figure, x, y, _, height, scalefactor)
7✔
170
  self:_ensureInit()
×
171
  x = SU.cast("number", x)
×
172
  y = SU.cast("number", y)
×
173
  height = SU.cast("number", height)
×
174
  pdf.add_content("q")
×
175
  self:setCursor(x, y)
×
176
  x, y = self:getCursor()
×
177
  local newy = y - SILE.documentState.paperSize[2] + height
×
178
  pdf.add_content(table.concat({ scalefactor, 0, 0, -scalefactor, x, newy, "cm" }, " "))
×
179
  pdf.add_content(figure)
×
180
  pdf.add_content("Q")
×
181
end
182

183
function outputter:drawRule (x, y, width, height)
7✔
184
  x = SU.cast("number", x)
×
185
  y = SU.cast("number", y)
×
186
  width = SU.cast("number", width)
×
187
  height = SU.cast("number", height)
×
188
  self:_ensureInit()
×
189
  local paperY = SILE.documentState.paperSize[2]
×
190
  pdf.setrule(x, paperY - y - height, width, height)
×
191
end
192

193
function outputter:debugFrame (frame)
7✔
194
  self:_ensureInit()
×
195
  self:pushColor({ r = 0.8, g = 0, b = 0 })
×
196
  self:drawRule(frame:left()-_dl/2, frame:top()-_dl/2, frame:width()+_dl, _dl)
×
197
  self:drawRule(frame:left()-_dl/2, frame:top()-_dl/2, _dl, frame:height()+_dl)
×
198
  self:drawRule(frame:right()-_dl/2, frame:top()-_dl/2, _dl, frame:height()+_dl)
×
199
  self:drawRule(frame:left()-_dl/2, frame:bottom()-_dl/2, frame:width()+_dl, _dl)
×
200
  -- self:drawRule(frame:left() + frame:width()/2 - 5, (frame:top() + frame:bottom())/2+5, 10, 10)
201
  local stuff = SILE.shaper:createNnodes(frame.id, debugfont)
×
202
  stuff = stuff[1].nodes[1].value.glyphString -- Horrible hack
×
203
  local buf = {}
×
204
  for i = 1, #stuff do
×
205
    buf[i] = glyph2string(stuff[i])
×
206
  end
207
  buf = table.concat(buf, "")
×
208
  self:_withDebugFont(function ()
×
209
    self:setCursor(frame:left():tonumber() - _dl/2, frame:top():tonumber() + _dl/2)
×
210
    self:_drawString(buf, 0, 0, 0)
×
211
  end)
212
  self:popColor()
×
213
end
214

215
function outputter:debugHbox (hbox, scaledWidth)
7✔
216
  self:_ensureInit()
×
217
  self:pushColor({ r = 0.8, g = 0.3, b = 0.3 })
×
218
  local paperY = SILE.documentState.paperSize[2]
×
219
  local x, y = self:getCursor()
×
220
  y = paperY - y
×
221
  self:drawRule(x-_dl/2, y-_dl/2-hbox.height, scaledWidth+_dl, _dl)
×
222
  self:drawRule(x-_dl/2, y-hbox.height-_dl/2, _dl, hbox.height+hbox.depth+_dl)
×
223
  self:drawRule(x-_dl/2, y-_dl/2, scaledWidth+_dl, _dl)
×
224
  self:drawRule(x+scaledWidth-_dl/2, y-hbox.height-_dl/2, _dl, hbox.height+hbox.depth+_dl)
×
225
  if hbox.depth > SILE.length(0) then
×
226
    self:drawRule(x-_dl/2, y+hbox.depth-_dl/2, scaledWidth+_dl, _dl)
×
227
  end
228
  self:popColor()
×
229
end
230

231
return outputter
7✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc