@@ -237,6 +237,7 @@ void SixelParser::_executeNextLine()
237
237
_imageCursor.y += _sixelHeight;
238
238
_availablePixelHeight -= _sixelHeight;
239
239
_resizeImageBuffer (_sixelHeight);
240
+ _fillImageBackgroundWhenScrolled ();
240
241
}
241
242
242
243
void SixelParser::_executeMoveToHome ()
@@ -342,10 +343,11 @@ void SixelParser::_initRasterAttributes(const VTInt macroParameter, const Dispat
342
343
// By default, the filled area will cover the maximum extent allowed.
343
344
_backgroundSize = { til::CoordTypeMax, til::CoordTypeMax };
344
345
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;
349
351
}
350
352
351
353
void SixelParser::_updateRasterAttributes (const VTParameters& rasterAttributes)
@@ -652,10 +654,6 @@ void SixelParser::_resizeImageBuffer(const til::CoordType requiredHeight)
652
654
{
653
655
static constexpr auto transparentPixel = IndexedPixel{ .transparent = true };
654
656
_imageBuffer.resize (requiredSize, transparentPixel);
655
- if (_resizeFillRequired)
656
- {
657
- _fillImageBackground (requiredHeight);
658
- }
659
657
}
660
658
}
661
659
@@ -667,13 +665,17 @@ void SixelParser::_fillImageBackground()
667
665
668
666
// When a background fill is requested, we prefill the buffer with the 0
669
667
// 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.
673
670
const auto backgroundHeight = std::min (_backgroundSize.height , _availablePixelHeight);
674
671
_resizeImageBuffer (backgroundHeight);
675
672
_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 ();
677
679
}
678
680
}
679
681
@@ -691,6 +693,33 @@ void SixelParser::_fillImageBackground(const int backgroundHeight)
691
693
_imageWidth = std::max (_imageWidth, backgroundWidth);
692
694
}
693
695
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
+
694
723
void SixelParser::_writeToImageBuffer (int sixelValue, int repeatCount)
695
724
{
696
725
// On terminals that support the raster attributes command (which sets the
@@ -731,11 +760,13 @@ void SixelParser::_eraseImageBufferRows(const int rowCount, const til::CoordType
731
760
const auto bufferOffsetEnd = bufferOffset + pixelCount * _imageMaxWidth;
732
761
if (static_cast <size_t >(bufferOffsetEnd) >= _imageBuffer.size ()) [[unlikely]]
733
762
{
763
+ _decreaseFilledBackgroundHeight (_imageCursor.y );
734
764
_imageBuffer.clear ();
735
765
_imageCursor.y = 0 ;
736
766
}
737
767
else
738
768
{
769
+ _decreaseFilledBackgroundHeight (pixelCount);
739
770
_imageBuffer.erase (_imageBuffer.begin () + bufferOffset, _imageBuffer.begin () + bufferOffsetEnd);
740
771
_imageCursor.y -= pixelCount;
741
772
}
0 commit comments