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

sile-typesetter / sile / 13909532704

17 Mar 2025 08:47PM UTC coverage: 58.465% (-8.1%) from 66.515%
13909532704

push

github

web-flow
Merge pull request #2237 from Omikhleia/feat-font-adjust

feat(core): Support ex-height and cap-height font adjustment

24 of 29 new or added lines in 3 files covered. (82.76%)

2396 existing lines in 68 files now uncovered.

12515 of 21406 relevant lines covered (58.46%)

3110.86 hits per line

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

83.67
/pagebuilders/base.lua
1
--- SILE pagebuilder class.
2
-- @interfaces pagebuilders
3

4
local pagebuilder = pl.class()
28✔
5
pagebuilder.type = "pagebuilder"
28✔
6
pagebuilder._name = "base"
28✔
7

8
function pagebuilder:_init ()
28✔
9
   self.awful_bad = 1073741823
28✔
10
   self.inf_bad = 10000
28✔
11
   self.eject_penalty = -self.inf_bad
28✔
12
   self.deplorable = 100000
28✔
13
end
14

15
function pagebuilder.collateVboxes (_, vboxlist)
28✔
16
   local output = SILE.types.node.vbox()
2✔
17
   output:append(vboxlist)
2✔
18
   return output
2✔
19
end
20

21
-- Note: Almost 1/3 of the time in a typical SILE in taken iterating through
22
-- this function. As a result there are some micro-optimizations here that
23
-- make it a-typical of preferred coding styles. In particular note that
24
-- we absolutize heavily iterated lengths as early as possible and make
25
-- make direct calls to their integer amounts, assumed to be in points by
26
-- the point they are called **without actually checking**!
27
function pagebuilder:findBestBreak (options)
28✔
28
   local vboxlist = SU.required(options, "vboxlist", "in findBestBreak")
483✔
29
   local target = SU.required(options, "target", "in findBestBreak", "length")
483✔
30
   local restart = options.restart or false
483✔
31
   local force = options.force or false
483✔
32
   local i = 0
483✔
33
   local totalHeight = SILE.types.length()
483✔
34
   local bestBreak = nil
483✔
35
   local started = false
483✔
36
   if restart and restart.target == target then
483✔
37
      totalHeight = restart.totalHeight
×
38
      i = restart.i
×
39
      started = restart.started
×
40
   end
41
   local leastC = self.inf_bad
483✔
42
   SU.debug("pagebuilder", function ()
966✔
43
      return "Page builder for frame "
×
44
         .. SILE.typesetter.frame.id
×
45
         .. " called with "
×
46
         .. #vboxlist
×
47
         .. " nodes, "
×
48
         .. tostring(target)
×
49
   end)
50
   if SU.debugging("vboxes") then
966✔
51
      for j, box in ipairs(vboxlist) do
×
52
         SU.debug("vboxes", function ()
×
53
            return (j == i and " >" or "  ") .. j .. ": " .. box
×
54
         end)
55
      end
56
   end
57
   while not started and i < #vboxlist do
1,171✔
58
      i = i + 1
1,156✔
59
      if not vboxlist[i].is_vglue then
1,156✔
60
         started = true
468✔
61
         i = i - 1
468✔
62
         break
468✔
63
      end
64
   end
65
   local pi
66
   while i < #vboxlist do
7,735✔
67
      i = i + 1
7,309✔
68
      local vbox = vboxlist[i]
7,309✔
69
      SU.debug("pagebuilder", "Dealing with VBox", vbox)
7,309✔
70
      if vbox.is_vbox then
7,309✔
71
         totalHeight:___add(vbox.height)
2,218✔
72
         totalHeight:___add(vbox.depth)
4,436✔
73
      elseif vbox.is_vglue then
5,091✔
74
         totalHeight:___add(vbox.height)
7,860✔
75
      elseif vbox.is_insertion then
1,161✔
76
         -- TODO: refactor as hook and without side effects!
77
         target = SILE.insertions.processInsertion(vboxlist, i, totalHeight, target)
10✔
78
         vbox = vboxlist[i]
5✔
79
      end
80
      local left = target - totalHeight
7,309✔
81
      SU.debug("pagebuilder", "I have", left, "left")
7,309✔
82
      -- if left < -20 then SU.error("\nCatastrophic page breaking failure!"); end
83
      pi = 0
7,309✔
84
      if vbox.is_penalty then
7,309✔
85
         pi = vbox.penalty
1,157✔
86
      end
87
      if
88
         vbox.is_penalty and vbox.penalty < self.inf_bad
7,309✔
89
         or (vbox.is_vglue and i > 1 and not vboxlist[i - 1].discardable)
6,705✔
90
      then
91
         local badness
92
         SU.debug("pagebuilder", "totalHeight", totalHeight, "with target", target)
2,372✔
93
         if totalHeight.length.amount < target.length.amount then -- TeX #1039
2,372✔
94
            -- Account for infinite stretch?
95
            badness = SU.rateBadness(self.inf_bad, left.length.amount, totalHeight.stretch.amount)
4,706✔
96
         elseif left.length.amount < totalHeight.shrink.amount then
19✔
97
            badness = self.awful_bad
17✔
98
         else
99
            badness = SU.rateBadness(self.inf_bad, -left.length.amount, totalHeight.shrink.amount)
4✔
100
         end
101

102
         local c
103
         if badness < self.awful_bad then
2,372✔
104
            if pi <= self.eject_penalty then
2,355✔
105
               c = pi
40✔
106
            elseif badness < self.inf_bad then
2,315✔
107
               c = badness + pi -- plus insert
72✔
108
            else
109
               c = self.deplorable
2,243✔
110
            end
111
         else
112
            c = badness
17✔
113
         end
114
         if c < leastC then
2,372✔
115
            leastC = c
111✔
116
            bestBreak = i
111✔
117
         else
118
            restart = { totalHeight = totalHeight, i = i, started = started, target = target }
2,261✔
119
         end
120

121
         SU.debug("pagebuilder", "Badness:", c)
2,372✔
122
         if c == self.awful_bad or pi <= self.eject_penalty then
2,372✔
123
            SU.debug("pagebuilder", "outputting")
57✔
124
            local onepage = {}
57✔
125
            if not bestBreak then
57✔
126
               bestBreak = i
16✔
127
            end
128
            for j = 1, bestBreak do
904✔
129
               onepage[j] = table.remove(vboxlist, 1)
1,694✔
130
            end
131
            while #onepage > 1 and onepage[#onepage].discardable do
115✔
132
               onepage[#onepage] = nil
58✔
133
            end
134
            return onepage, pi
57✔
135
         end
136
      end
137
   end
138
   SU.debug("pagebuilder", "No page break here")
426✔
139
   if force and bestBreak then
426✔
UNCOV
140
      local onepage = {}
×
UNCOV
141
      for j = 1, bestBreak do
×
UNCOV
142
         onepage[j] = table.remove(vboxlist, 1)
×
143
      end
UNCOV
144
      return onepage, pi
×
145
   end
146
   return false, restart
426✔
147
end
148

149
return pagebuilder
28✔
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

© 2026 Coveralls, Inc