Skip to content

Commit 1281683

Browse files
committed
Improve correctness of Sixel background fill (take 2)
1 parent 877bfe7 commit 1281683

File tree

2 files changed

+46
-13
lines changed

2 files changed

+46
-13
lines changed

src/terminal/adapter/SixelParser.cpp

+43-12
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,7 @@ void SixelParser::_executeNextLine()
237237
_imageCursor.y += _sixelHeight;
238238
_availablePixelHeight -= _sixelHeight;
239239
_resizeImageBuffer(_sixelHeight);
240+
_fillImageBackgroundWhenScrolled();
240241
}
241242

242243
void SixelParser::_executeMoveToHome()
@@ -342,10 +343,11 @@ void SixelParser::_initRasterAttributes(const VTInt macroParameter, const Dispat
342343
// By default, the filled area will cover the maximum extent allowed.
343344
_backgroundSize = { til::CoordTypeMax, til::CoordTypeMax };
344345

345-
// If the requested background area can not initially be filled, we'll
346-
// handle the rest of it on demand when the image is resized. But this
347-
// will be determined later in the _fillImageBackground method.
348-
_resizeFillRequired = false;
346+
// If the image ends up extending beyond the bottom of the page, we may need
347+
// to perform additional background filling as the screen is scrolled, which
348+
// requires us to track the area filled so far. This will be initialized, if
349+
// necessary, in the _fillImageBackground method below.
350+
_filledBackgroundHeight = std::nullopt;
349351
}
350352

351353
void SixelParser::_updateRasterAttributes(const VTParameters& rasterAttributes)
@@ -652,10 +654,6 @@ void SixelParser::_resizeImageBuffer(const til::CoordType requiredHeight)
652654
{
653655
static constexpr auto transparentPixel = IndexedPixel{ .transparent = true };
654656
_imageBuffer.resize(requiredSize, transparentPixel);
655-
if (_resizeFillRequired)
656-
{
657-
_fillImageBackground(requiredHeight);
658-
}
659657
}
660658
}
661659

@@ -667,13 +665,17 @@ void SixelParser::_fillImageBackground()
667665

668666
// When a background fill is requested, we prefill the buffer with the 0
669667
// color index, up to the boundaries set by the raster attributes (or if
670-
// none were given, up to the page boundaries). If the requested height
671-
// is more than the available height, we'll continue filling the rest of
672-
// it on demand when the image is resized (see above).
668+
// none were given, up to the page boundaries). The actual image output
669+
// isn't limited by the background dimensions though.
673670
const auto backgroundHeight = std::min(_backgroundSize.height, _availablePixelHeight);
674671
_resizeImageBuffer(backgroundHeight);
675672
_fillImageBackground(backgroundHeight);
676-
_resizeFillRequired = _backgroundSize.height > _availablePixelHeight;
673+
// When the image extends beyond the page boundaries, and the screen is
674+
// scrolled, we also need to fill the newly exposed lines, so we keep a
675+
// record of the area filled so far. Initially this is considered to be
676+
// the available height, even if it wasn't all filled to start with.
677+
_filledBackgroundHeight = _imageCursor.y + _availablePixelHeight;
678+
_fillImageBackgroundWhenScrolled();
677679
}
678680
}
679681

@@ -691,6 +693,33 @@ void SixelParser::_fillImageBackground(const int backgroundHeight)
691693
_imageWidth = std::max(_imageWidth, backgroundWidth);
692694
}
693695

696+
void SixelParser::_fillImageBackgroundWhenScrolled()
697+
{
698+
// If _filledBackgroundHeight is set, that means a background fill has been
699+
// requested, and we need to extend that area whenever the image is about to
700+
// overrun it. The newly filled area is a multiple of the cell height (this
701+
// is to match the behavior of the original hardware terminals).
702+
const auto imageHeight = _imageCursor.y + _sixelHeight;
703+
if (_filledBackgroundHeight && imageHeight > _filledBackgroundHeight) [[unlikely]]
704+
{
705+
_filledBackgroundHeight = (imageHeight + _cellSize.height - 1) / _cellSize.height * _cellSize.height;
706+
const auto additionalFillHeight = _filledBackgroundHeight.value() - _imageCursor.y;
707+
_resizeImageBuffer(additionalFillHeight);
708+
_fillImageBackground(additionalFillHeight);
709+
}
710+
}
711+
712+
void SixelParser::_decreaseFilledBackgroundHeight(const int decreasedHeight)
713+
{
714+
// Sometimes the top of the image buffer may be clipped (e.g. when the image
715+
// scrolls off the top of a margin area). When that occurs, our record of
716+
// the filled height will need to be decreased to account for the new start.
717+
if (_filledBackgroundHeight) [[unlikely]]
718+
{
719+
_filledBackgroundHeight = _filledBackgroundHeight.value() - decreasedHeight;
720+
}
721+
}
722+
694723
void SixelParser::_writeToImageBuffer(int sixelValue, int repeatCount)
695724
{
696725
// On terminals that support the raster attributes command (which sets the
@@ -731,11 +760,13 @@ void SixelParser::_eraseImageBufferRows(const int rowCount, const til::CoordType
731760
const auto bufferOffsetEnd = bufferOffset + pixelCount * _imageMaxWidth;
732761
if (static_cast<size_t>(bufferOffsetEnd) >= _imageBuffer.size()) [[unlikely]]
733762
{
763+
_decreaseFilledBackgroundHeight(_imageCursor.y);
734764
_imageBuffer.clear();
735765
_imageCursor.y = 0;
736766
}
737767
else
738768
{
769+
_decreaseFilledBackgroundHeight(pixelCount);
739770
_imageBuffer.erase(_imageBuffer.begin() + bufferOffset, _imageBuffer.begin() + bufferOffsetEnd);
740771
_imageCursor.y -= pixelCount;
741772
}

src/terminal/adapter/SixelParser.hpp

+3-1
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ namespace Microsoft::Console::VirtualTerminal
8989
til::CoordType _pendingTextScrollCount = 0;
9090
til::size _backgroundSize;
9191
bool _backgroundFillRequired = false;
92-
bool _resizeFillRequired = false;
92+
std::optional<til::CoordType> _filledBackgroundHeight;
9393

9494
void _initColorMap(const VTParameter backgroundColor);
9595
void _defineColor(const VTParameters& colorParameters);
@@ -111,6 +111,8 @@ namespace Microsoft::Console::VirtualTerminal
111111
void _resizeImageBuffer(const til::CoordType requiredHeight);
112112
void _fillImageBackground();
113113
void _fillImageBackground(const int backgroundHeight);
114+
void _fillImageBackgroundWhenScrolled();
115+
void _decreaseFilledBackgroundHeight(const int decreasedHeight);
114116
void _writeToImageBuffer(const int sixelValue, const int repeatCount);
115117
void _eraseImageBufferRows(const int rowCount, const til::CoordType startRow = 0) noexcept;
116118
void _maybeFlushImageBuffer(const bool endOfSequence = false);

0 commit comments

Comments
 (0)