This optimizes the normal scrolling case; updates are done at the
bottom of the screen and then scrolled up.
In this case, the damage list will be a more or less sorted list of
updates, oldest first.
If we're scrolling a lot, the oldest updates will eventually scroll
off screen. In this case, there's no need to keep them in the damage
list.
So, when scrolling, loop the damage list and adjust/remove updates
that have scrolled off screen (either partially, or completely).
Stop looping as soon as we see an update that has *not* scrolled off
screen.
Note that this means there may be update items in the damage list
that *has* scrolled off screen. This is especially true for random
screen writes (i.e. typical to some synthetic benchmarks).
This adds a pointer to the first cell on the current line. This
pointer must be updated every time the row changes.
The advantage is mainly that PRINT doesn't have to call
grid_get_range(), which is fairly expensive.
Since horizontal cursor movement is clamped to the current line, we
can calculate the new linear cursor without any expensive
multiplications and/or divisions.
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.