Commit graph

582 commits

Author SHA1 Message Date
Daniel Eklöf
37b15adcd8
term: turn ‘box-drawings’ array into three dynamically allocated arrays
The box_drawings array is now quite large, and uses up ~4K
when *empty*.

This patch splits it up into three separate, dynamically allocated
arrays; one for the traditional box+line drawing and block elements
glyphs, one for braille, and one for the legacy computing symbols.

When we need to render a glyph, the *entire* array (that it belongs
to) is allocated.

I.e this is one step closer to a dynamic glyph cache (like the one
fcft uses), but doesn’t go all the way.

This is especially nice for people with
‘box-drawings-uses-font-glyphs=yes’; for them, the custom glyphs now
uses 3*8 bytes (for the three array pointers), instead of 4K.
2021-09-14 09:50:49 +02:00
Daniel Eklöf
896825f50c
render: codespell: aquire -> acquire 2021-09-12 19:22:14 +02:00
Daniel Eklöf
b4c759e2de
box-drawing: add braille characters
Render braille ourselves, instead of using font glyphs. Decoding a
braille character is easy enough; there are 256 codepoints,
represented by an 8-bit integer (i.e. subtract the Unicode codepoint
offset, 0x2800, and you’re left with an integer in the range 0-255).

Each bit corresponds to a dot. The first 6 bits represent the upper 6
dots, while the two last bits represent the fourth (and last) row of
dots.

The hard part is sizing the dots and the spacing between them.

The aim is to have the spacing between the dots be the same size as
the dots themselves, and to have the margins on each side be half the
size of the dots.

In a perfectly sized cell, this means two braille characters next to
each other will be evenly spaced.

This is however almost never the case. The layout logic currently:

* Set dot size to either the width / 4, or height / 8, depending on
  which one is smallest.

* Horizontal spacing is initialized to the width / 4

* Vertical spacing is initialized to the height / 8

* Horizontal margins are initialized to the horizontal spacing / 2

* Vertical margins are initialized to the vertical spacing / 2.

Next, we calculate the number of “remaining” pixels. That is, if we
add the left margin, two dots and the spacing between, how many pixels
are left on the horizontal axis?

These pixels are distributed in the following order (we “stop” as soon
as we run out of pixels):

* If the dot size is 0 (happens for very small font sizes), increase
  it to 1.
* If the margins are 0, increase them to 1.
* If we have enough pixels (need at 2 horizontal and 4 vertical),
  increase the dot size.
* Increase spacing.
* Increase margins.

Closes #702
2021-09-12 19:22:12 +02:00
Daniel Eklöf
26859a5168
render: unref clip region 2021-09-04 20:08:23 +02:00
Daniel Eklöf
ae70596a50
selection: don’t require two cell attr bits for selection updating
When updating the selection (i.e when changing it - adding or removing
cells to the selection), we need to do two things:

* Unset the ‘selected’ bit on all cells that are no longer selected.
* Set the ‘selected’ bit on all cells that *are* selected.

Since it’s quite tricky to calculate the difference between the “old”
and “new” selection, this is done by first un-selecting the old
selection, and then selecting the new, updated selection. I.e. first
we clear the ‘selected’ bit from *all* cells, and then we re-set it on
those cells that are still selected.

This process also dirties the cells, to make sure they are
re-rendered (needed to reflect their new selected/un-selected status).

To avoid dirtying *all* previously selected, and newly selected cells,
we have used an algorithm that first runs a “pre-pass”, marking all
cells that *will* be selected as such. The un-select pass would then
skip (no dirty) cells that have been marked by the pre-pass. Finally,
the select pass would only dirty cells that have *not* been marked by
the pre-pass.

In short, we only dirty cells whose selection state have *changed*.

To do this, we used a second ‘selected’ bit in the cell attribute
struct.

Those bits are *scarce*.

This patch implements an alternative algorithm, that frees up one of
the two ‘selected’ bits.

This is done by lazy allocating a bitmask for the entire grid. The
pre-pass sets bits in the bitmask. Thus, after the pre-pass, the
bitmask has set bits for all cells that *will* be selected.

The un-select pass simply skips cells with a one-bit in the
bitmask. Cells without a one-bit in the bitmask are dirtied, and their
‘selected’ bit is cleared.

The select-pass doesn’t even have to look at the bitmask - if the cell
already has its ‘selected’ bit set, it does nothing. Otherwise it sets
it and dirties the cell.

The bitmask is implemented as an array of arrays of 64-bit
integers. Each outer element represents one row. These pointers are
calloc():ed before starting the pre-pass.

The pre-pass allocates the inner arrays on demand.

The unselect pass is designed to handle both the complete absence of a
bitmask, as well as row entries being NULL (both means the cell
is *not* pre-marked, and will thus be dirtied).
2021-08-16 19:15:41 +02:00
Daniel Eklöf
41a8f2fc65
render: run the “overflowing glyphs” prepass *before* rendering sixels
This fixes an issue where the left-most column of a sixel was
“overwritten” by the cell content.

This patch also rewrites the prepass logic, to try to reduce the
number of loads performed.

The new logic loops each row from left to right, looking for dirty
cells. When a dirty cell is found, we first scan backwards, until we
find a non-overflowing cell. That cell is unaffected by the
overflowing cell we’re currently dealing with.

We can also stop as soon as we see a dirty cell, since that cell will
already have been dealt with.

Then, we scan forward, dirtying cells until we see a non-overflowing
cell. That first non-overflowing cell is also dirtied, but after that
we break.

The last loop, that scans forward, advances the same cell pointer used
in the outer loop.
2021-08-11 18:26:00 +02:00
Daniel Eklöf
1c43fdbea4
box-drawing: add U+1FB3C-U+1FB6F, U+1FB9A and U+1FB9B
These are the “wedges” from the Unicode 13 “Legacy Computing” symbols.

Closes #474
2021-08-05 18:25:01 +02:00
Daniel Eklöf
03f952cf4d
term: consolidate shutdown related state into an anonymous struct 2021-07-31 19:08:51 +02:00
Daniel Eklöf
384b1c330f
term: asynchronous client application termination
When the foot window is closed, and we need to terminate the client application,
do this in an asynchronous fashion:

* Don’t do a blocking call to waitpid(), instead, rely on the reaper callback
* Use a timer FD to implement the timeout before sending SIGKILL (instead of
  using SIGALRM).
* Send SIGTERM immediately (we used to *just* close the PTY, and then wait 2
  seconds before sending SIGTERM).
* Raise the timeout from 2 seconds to 60

Full shutdown now depends on *two* asynchronous tasks - unmapping the window,
and waiting for the client application to terminate.

Only when *both* of these have completed do we proceed and call term_destroy(),
and the user provided shutdown callback.
2021-07-31 18:18:48 +02:00
David Rosca
2c5a23867f
Only brighten palette colors with bold-text-in-bright=palette-based 2021-07-26 19:13:46 +02:00
Daniel Eklöf
7714fcde83
render: render_osd(): use fcft_text_run_rasterize(), if available 2021-07-24 11:02:43 +02:00
Daniel Eklöf
e2e28db7de
render: render_osd(): fix rendering of color bitmap glyphs 2021-07-24 11:02:43 +02:00
Daniel Eklöf
bf285ae00a
render: render_osd(): don’t re-instantiate foreground color for each glyph 2021-07-24 11:02:43 +02:00
Daniel Eklöf
5c683d2c08
render: render_osd(): don’t assume a monospace font 2021-07-24 11:02:43 +02:00
Daniel Eklöf
0cf7a19616
render: csd_title(): use a custom font, sized based on the title bar’s height
We still use the primary font, but use a custom size, based on the
title bar’s height.

This fixes an issue where the window title could be way too small, or
way too big. And changed size when the terminal font size was changed.
2021-07-24 11:02:42 +02:00
Daniel Eklöf
4a41575cb5
render: render_osd() now needs a ‘font’ argument 2021-07-24 11:02:42 +02:00
Daniel Eklöf
5fe23c0215
render: render_osd(): pass font as argument 2021-07-24 11:02:42 +02:00
Daniel Eklöf
3d9536caff
render: refresh CSD in render_refresh_title(), not render_update_title()
This fixes an issue where the CSD title sometimes got stuck on an
“old” title.
2021-07-24 11:02:42 +02:00
Daniel Eklöf
61e4035c23
render: refresh CSDs when updating the title 2021-07-24 11:02:42 +02:00
Daniel Eklöf
468587b67f
render: csd_title(): use render_osd() to render the current window title 2021-07-24 11:02:42 +02:00
Daniel Eklöf
bbc26da87b
render: must now set alpha in bg color when calling render_osd() 2021-07-24 11:02:42 +02:00
Daniel Eklöf
7067c57399
render: render_osd(): set clip region, use background alpha
Set clip region in render_osd(). This ensures we don’t step outside
the pixman buffer when rendering the glyphs.

Furthermore, don’t ignore the alpha channel in the background color.

Move render_osd() to make it visible to the render_csd_*() functions.
2021-07-24 11:02:41 +02:00
Daniel Eklöf
e17c6fcbec
render: color_dim(): retain alpha channel 2021-07-24 11:02:41 +02:00
Timur Celik
a410734f96 render: prevent cells from overflowing into margin 2021-07-20 11:44:27 +02:00
Daniel Eklöf
20fc80e57e
render: use a single backing SHM pool for CSD surface buffers 2021-07-18 16:46:43 +02:00
Daniel Eklöf
53851e13ec
shm: refactor: move away from a single, global, buffer list
Up until now, *all* buffers have been tracked in a single, global
buffer list. We've used 'cookies' to separate buffers from different
contexts (so that shm_get_buffer() doesn't try to re-use e.g. a
search-box buffer for the main grid).

This patch refactors this, and completely removes the global
list.

Instead of cookies, we now use 'chains'. A chain tracks both the
properties to apply to newly created buffers (scrollable, number of
pixman instances to instantiate etc), as well as the instantiated
buffers themselves.

This means there's strictly speaking not much use for shm_fini()
anymore, since its up to the chain owner to call shm_chain_free(),
which will also purge all buffers.

However, since purging a buffer may be deferred, if the buffer is
owned by the compositor at the time of the call to shm_purge() or
shm_chain_free(), we still keep a global 'deferred' list, on to which
deferred buffers are pushed. shm_fini() iterates this list and
destroys the buffers _even_ if they are still owned by the
compositor. This only happens at program termination, and not when
destroying a terminal instance. I.e. closing a window in a “foot
--server” does *not* trigger this.

Each terminal instatiates a number of chains, and these chains are
destroyed when the terminal instance is destroyed. Note that some
buffers may be put on the deferred list, as mentioned above.
2021-07-17 19:14:42 +02:00
Daniel Eklöf
232fb20269
shm: replace 'locked' attribute with a ref-counter
The initial ref-count is either 1 or 0, depending on whether the
buffer is supposed to be released "immeidately" (meaning, as soon as
the compositor releases it).

Two new user facing functions have been added: shm_addref() and
shm_unref().

Our renderer now uses these two functions instead of manually setting
and clearing the 'locked' attribute.

shm_unref() will decrement the ref-counter, and destroy the buffer
when the counter reaches zero. Except if the buffer is currently
"busy" (compositor owned), in which case destruction is deferred to
the release event. The buffer is still removed from the list though.
2021-07-17 19:14:42 +02:00
Daniel Eklöf
69260dd960
shm: we may exit with busy buffers remaining (seen on KDE) 2021-07-17 19:14:41 +02:00
Daniel Eklöf
99ea47c97a
shm: move ‘size’ to the private buffer struct 2021-07-17 19:14:41 +02:00
Daniel Eklöf
9b6cee825b
shm: rename buffer.mmapped to buffer.data 2021-07-17 19:14:41 +02:00
Timur Celik
91801ae55d render: Allow cells to bleed into their neighbor
This patch adds a `confined` flag to each cell to track if the last
rendered glyph bled into it's right neighbor.  To keep things simple,
bleeding into any other neighbor cell than the immediate right one is
not allowed.  This should cover most use cases.

Before rendering a row we now do a prepass and mark all cells unclean
that are affected by a bleeding neighbor.  If there are consecutive
bleeding cells, the whole group must be re-rendered even if only a
single cell has changed.

The patch also deprecates both old overflowing glyph options
*allow-overflowing-double-width-glyphs* and *pua-double-width* in favor
of a single new one named *overflowing-glyphs*.
2021-07-17 13:22:44 +02:00
Daniel Eklöf
31fad58465
url-mode: use shm_get_many()
If we have lots of URLs, we use up a *lot* of SHM buffers (and thus
pools). Each and every one is a single mmap(), of at least 4K.

Since all URL labels are created and destroyed at the same time, it
makes sense to use a single pool for all buffers.

To do this, we must now do two passes; first one to generate the
actual string (label content), and to calculate the label sizes.

Then we use this information to allocate all SHM buffers at once, from
the same pool.

Finally, we iterate the URLs again, this time to actually render them.
2021-07-15 18:39:41 +02:00
Daniel Eklöf
7533684d8f
shm: add shm_get_many() - allows buffers to share a single pool
shm_get_many() always returns new buffers (i.e. never old, cached
ones). The newly allocated buffers are also marked for immediate
purging, meaning they’ll be destroyed on the next call to either
shm_get_buffer(), or shm_get_many().

Furthermore, we add a new attribute, ‘locked’, to the buffer
struct. When auto purging buffers, look at this instead of comparing
cookies.

Buffer consumers are expected to set ‘locked’ while they hold a
reference to it, and don’t want it destroyed behind their back.
2021-07-15 18:39:23 +02:00
Daniel Eklöf
5e64c67c25
render: search: set clip region
Fixes crash when the search box has been reduced in height, due to
limited window space.
2021-07-15 18:27:10 +02:00
Daniel Eklöf
628fd39098
render: scrollback indicator: improve handling of very small window sizes 2021-07-15 18:26:26 +02:00
Daniel Eklöf
e259f460f3
render: margins: use correct background color
* Sync actual color used, with how render_cell() selects the
  background color
* Use color_dim_for_search(), not color_dim()
2021-07-15 18:24:27 +02:00
Daniel Eklöf
fcc2e62a7d
render: track alpha directly, rather whether to use it or not 2021-07-15 18:23:49 +02:00
Daniel Eklöf
9658e9cc18
render: tiocswinsz: don’t remove/close the fd passed as argument
There’s a chance the resize timeout FD was closed, and *reused*, after
epoll() told us the FD is readable, but before our callback runs.

Thus, closing the FD provided as an argument is dangerous, as it may
refer to something completely different.
2021-07-14 20:14:10 +02:00
Daniel Eklöf
0c777d825d
Revert "render: don’t assume PIXMAN_a8r8g8b8 for color glyphs"
This reverts commit 9b4796e996.

Sub-pixel anti-aliasing also uses 32-bit glyphs (but x8r8g8b8, instead
of a8r8g8b8)...
2021-07-14 19:56:11 +02:00
Daniel Eklöf
9b4796e996
render: don’t assume PIXMAN_a8r8g8b8 for color glyphs
We may want to use PIXMAN_b8g8r8a8 on big-endian in the future.
2021-07-14 19:46:18 +02:00
Daniel Eklöf
85b63b5e4a
render: require glyph count > 0 and cell-cols also for forced double-width PUAs 2021-07-02 16:48:46 +02:00
Daniel Eklöf
396a5ff79b
allow-overflowing-double-width-glyphs: take glyph offset into account
A narrow, but offset:ed glyph should still be considered double
width.

This patch also fixes a crash, when the maybe-double width glyph is in
the last column. This is a regression.
2021-07-02 16:31:14 +02:00
Daniel Eklöf
cf46acc68f
render: don’t look at glyphs[0]->cols when determining if overflow should be allowed
Use ‘cell_cols’ instead, which is the number of cells we’ll actually
be using.
2021-06-30 18:01:03 +02:00
Daniel Eklöf
fe8ca23cfe
composed: store compose chains in a binary search tree
The previous implementation stored compose chains in a dynamically
allocated array. Adding a chain was easy: resize the array and append
the new chain at the end. Looking up a compose chain given a compose
chain key/index was also easy: just index into the array.

However, searching for a pre-existing chain given a codepoint sequence
was very slow. Since the array wasn’t sorted, we typically had to scan
through the entire array, just to realize that there is no
pre-existing chain, and that we need to add a new one.

Since this happens for *each* codepoint in a grapheme cluster, things
quickly became really slow.

Things were ok:ish as long as the compose chain struct was small, as
that made it possible to hold all the chains in the cache. Once the
number of chains reached a certain point, or when we were forced to
bump maximum number of allowed codepoints in a chain, we started
thrashing the cache and things got much much worse.

So what can we do?

We can’t sort the array, because

a) that would invalidate all existing chain keys in the grid (and
iterating the entire scrollback and updating compose keys is *not* an
option).

b) inserting a chain becomes slow as we need to first find _where_ to
insert it, and then memmove() the rest of the array.

This patch uses a binary search tree to store the chains instead of a
simple array.

The tree is sorted on a “key”, which is the XOR of all codepoints,
truncated to the CELL_COMB_CHARS_HI-CELL_COMB_CHARS_LO range.

The grid now stores CELL_COMB_CHARS_LO+key, instead of
CELL_COMB_CHARS_LO+index.

Since the key is truncated, collisions may occur. This is handled by
incrementing the key by 1.

Lookup is of course slower than before, O(log n) instead of
O(1).

Insertion is slightly slower as well: technically it’s O(log n)
instead of O(1). However, we also need to take into account the
re-allocating the array will occasionally force a full copy of the
array when it cannot simply be growed.

But finding a pre-existing chain is now *much* faster: O(log n)
instead of O(n). In most cases, the first lookup will either
succeed (return a true match), or fail (return NULL). However, since
key collisions are possible, it may also return false matches. This
means we need to verify the contents of the chain before deciding to
use it instead of inserting a new chain. But remember that this
comparison was being done for each and every chain in the previous
implementation.

With lookups being much faster, and in particular, no longer requiring
us to check the chain contents for every singlec chain, we can now use
a dynamically allocated ‘chars’ array in the chain. This was
previously a hardcoded array of 10 chars.

Using a dynamic allocated array means looking in the array is slower,
since we now need two loads: one to load the pointer, and a second to
load _from_ the pointer.

As a result, the base size of a compose chain (i.e. an “empty” chain)
has now been reduced from 48 bytes to 32. A chain with two codepoints
is 40 bytes. This means we have up to 4 codepoints while still using
less, or the same amount, of memory as before.

Furthermore, the Unicode random test (i.e. write random “unicode”
chars) is now **faster** than current master (i.e. before text-shaping
support was added), **with** test-shaping enabled. With text-shaping
disabled, we’re _even_ faster.
2021-06-24 17:30:49 +02:00
Daniel Eklöf
b14524215b
render: use cell cols from compose chain, not grapheme
fcft’s view of how many columns a grapheme cluster is may differ from
our own. Make sure the rendered glyph matches the number of columns
that were allocated when the cluster was printed.
2021-06-24 17:30:48 +02:00
Daniel Eklöf
c0d9f92e1a
render: don’t modify the cell’s x position. Fixes broken underlines 2021-06-24 17:30:47 +02:00
Daniel Eklöf
51295cd7a2
render: we’ve already assigned ‘base’ a couple of lines higher up 2021-06-24 17:30:46 +02:00
Daniel Eklöf
96ff29bbd3
render: repair parenthesis after rebase 2021-06-24 17:30:46 +02:00
Daniel Eklöf
b471fe31b1
render: ensure ‘cell_cols’ have been initialized 2021-06-24 17:30:46 +02:00
Daniel Eklöf
50be924285
render: handle fcft_glyph_rasterize() failure correctly 2021-06-24 17:30:46 +02:00