The grid is now represented with an array of row *pointers*. Each row
contains an array of cells (the row's columns).
The main point of having row pointers is we can now move rows around
almost for free.
This is useful when scrolling with scroll margins for example, where
we previously had to copy the lines in the margins. Now it's just a
matter of swapping two pointers.
If a client writes to the PTY "too slow", we often end up flashing the
screen. This could for example be caused by a client first erasing a
line, then we render that frame, followed by the client updating the
just-erased line. When we render _that_ frame, it will be perceived as
a flash.
Mitigate this by trying to read client data again, after finishing
processing one batch, but before rendering.
To avoid hanging on client output (and never rendering anything),
limit this to at most 3 iterations. This may have to be tweaked.
Cache rendered glyph masks for each font combo. When rendering text,
use these when possible (standard ASCII).
For now, use the cached glyph as a mask. This allows colors to just
work. It would be faster to cache a completely pre-rendered image, but
then we would need one image for each background/foreground combo.
This means we don't have to explicitly set the foreground/background
to the grid's default colors whenever we reset/clear a cell, and we
can instead simply memset() the entire cell to 0.
This also means the renderer has to get the default color when
rendering a cell without a foreground/background color set.
Vim, for example, changes the scroll region every time you scroll a
single line. Thus, resetting the damage queue is slow.
This reworks the damage handling of scroll updates:
* Split damage queue into two: one for scroll operations and one for
update/erase operations.
* Don't separate update/erase operations inside/outside the scroll
region
* Store the current scroll region in the scroll damage operation. This
allows us to stack multiple scroll operations with different scroll
regions.
* When updating update/erase operations after a scroll operation,
split the update/erase operations if necessary (the current scroll
operation may have a scroll region different from before, thus
forcing us to split existing update/erase operations.
* The renderer no longer erases after a scroll. The scroll operation
also adds an erase operation. This also means that erase operation
are subject to adjustments by later scroll operations.