Merge remote-tracking branch 'upstream' into image-ext

This commit is contained in:
Per Bothner
2026-06-07 13:47:27 -07:00
418 changed files with 7902 additions and 4052 deletions
+26 -20
View File
@@ -5,12 +5,13 @@
import { IDisposable } from '@xterm/xterm';
import { ImageRenderer } from './ImageRenderer';
import type { ITerminalExt, IImageAddonOptions, IImageSpec, ICellSize, ImageLayer } from './Types';
import type { IBufferLine } from 'common/Types';
import type {
ITerminalExt, IImageAddonOptions, IImageSpec, ICellSize, IAddImageOpts
} from './Types';
import type { IBufferLine } from 'common/buffer/Types';
import { CellData } from 'common/buffer/CellData';
// fallback default cell size
export const CELL_SIZE_DEFAULT: ICellSize = {
width: 7,
@@ -158,13 +159,15 @@ export class ImageStorage implements IDisposable {
/**
* Method to add an image to the storage.
* @param img - The image to add (canvas or bitmap).
* @param scrolling - When true, cursor advances with the image (lineFeed per row).
* When false, image is placed at (0,0) and cursor is restored (DECSET 80 / sixel origin mode).
* @param layer - Which canvas layer to render on ('top' or 'bottom').
* @param zIndex - Z-index for image layering within the same layer.
* @param opts - Options for addImage:
* - scrolling: When true, cursor advances with the image.
* When false, image is placed at ORIGIN and cursor does not move.
* - layer: Which canvas layer to render on ('top' or 'bottom').
* - zIndex: Z-index for image layering within the same layer.
* - cursorPos: 'vt340' for bottom-left, 'iip' for bottom.right.
* @returns The internal image ID assigned to the stored image.
*/
public addImage(img: HTMLCanvasElement | ImageBitmap, scrolling: boolean, layer: ImageLayer = 'top', zIndex: number = 0): number {
public addImage(img: HTMLCanvasElement | ImageBitmap, opts: IAddImageOpts): number {
// never allow storage to exceed memory limit
this._evictOldest(img.width * img.height);
@@ -186,7 +189,7 @@ export class ImageStorage implements IDisposable {
let offset = originX;
let tileCount = 0;
if (!scrolling) {
if (!opts.scrolling) {
buffer.x = 0;
buffer.y = 0;
offset = 0;
@@ -200,7 +203,7 @@ export class ImageStorage implements IDisposable {
this._writeToCell(line, offset + col, imageId, row * cols + col);
tileCount++;
}
if (scrolling) {
if (opts.scrolling) {
if (row < rows - 1) this._terminal._core._inputHandler.lineFeed();
} else {
if (++buffer.y >= termRows) break;
@@ -210,8 +213,12 @@ export class ImageStorage implements IDisposable {
this._terminal._core._inputHandler._dirtyRowTracker.markDirty(buffer.y);
// cursor positioning modes
if (scrolling) {
buffer.x = offset;
if (opts.scrolling) {
if (opts.cursorPos === 'iip') {
buffer.x = Math.min(offset + cols, termCols);
} else {
buffer.x = offset;
}
} else {
buffer.x = originX;
buffer.y = originY;
@@ -254,8 +261,8 @@ export class ImageStorage implements IDisposable {
marker: endMarker || undefined,
tileCount,
bufferType: this._terminal.buffer.active.type,
layer,
zIndex
layer: opts.layer,
zIndex: opts.zIndex
};
// finally add the image
@@ -349,8 +356,8 @@ export class ImageStorage implements IDisposable {
const workCell = this._workCell;
for (let col = 0; col < cols; ++col) {
line.loadCell(col, workCell);
let e = workCell.hasExtendedAttrs() && workCell.extended.payload;
if (! (e instanceof ImageTileInfo)) {
const e = workCell.hasExtendedAttrs() && workCell.extended.payload;
if (!(e instanceof ImageTileInfo)) {
continue;
}
const imageId = e.imageId;
@@ -372,10 +379,9 @@ export class ImageStorage implements IDisposable {
while (++col < cols) {
line.loadCell(col, workCell);
const nextE = workCell.hasExtendedAttrs() && workCell.extended.payload;
if (! (nextE instanceof ImageTileInfo) || !nextE || nextE.imageId !== imageId || nextE.tileId !== startTile + count) {
if (!(nextE instanceof ImageTileInfo) || !nextE || nextE.imageId !== imageId || nextE.tileId !== startTile + count) {
break;
}
e = nextE;
count++;
}
col--;
@@ -425,11 +431,11 @@ export class ImageStorage implements IDisposable {
const oldCol = this._viewportMetrics.cols - 1;
const workCell = this._workCell;
for (let row = 0; row < rows; ++row) {
const line = buffer.lines.get(row) !;
const line = buffer.lines.get(row)!;
line.loadCell(oldCol, workCell);
if (workCell.hasExtendedAttrs()) {
const e = workCell.extended.payload;
if (! (e instanceof ImageTileInfo)) {
if (!(e instanceof ImageTileInfo)) {
continue;
}
const imageId = e.imageId;