@@ -237,6 +237,7 @@ void SixelParser::_executeNextLine()
237237 _imageCursor.y += _sixelHeight;
238238 _availablePixelHeight -= _sixelHeight;
239239 _resizeImageBuffer (_sixelHeight);
240+ _fillImageBackgroundWhenScrolled ();
240241}
241242
242243void 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
351353void 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+
694723void 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 }
0 commit comments