We were checking for an off-plane cursor destination on
the X axis when it was provided explicitly, but not when
-1 was used to indicate the current position (contradicting
the comment immediately above the test). We also want to do
so when we're using the current position, though in this
case scrolling must be taken into account. Also, we were
placing the cursor on such a validation failure, despite not
intending to write anything.
Not testing for a current x (the -1 case) usually worked
because it was thrown out by ncplane_move_cursor_yx() below.
That fails, however, when we're working with an EGC that's
more than one column.
Delicate!
ncplane_putc_yx() calls ncplane_put() using an EGC extracted
from its nccell argument. The very act of writing that cell
to the plane, however, can grow the plane's underlying EGCpool,
possibly invalidating this reference. This was showing up as
a unit test failure on macOS, and was hopefully also the cause
of unit test failures on Alpine i686. Do a quick heap copy of
the EGC in ncplane_putc_yx(), and free it after writing to the
plane. Shouldn't cost anything (there was no measurable
impact in my testing). Closes#2420.
When both foreground and background are using RGB, and
the two channels are the same RGB value, the glyph will
be invisible; emitting a space with the correct background
can save RGB escapes and glyph bytes. Eliminates several
longstanding FIXMEs in the Stacking unit tests. Add a new
function nccell_rgbequal_p(), and unit testing for it.
Add a new unit test to check that this optimization has
taken place, and that it has only taken place in the
rasterization phase--the original plane must be unchanged.
Closes#1316.