From 17575e1d7b7ed94b5c68cb5b88ffcd1dab754f75 Mon Sep 17 00:00:00 2001 From: tisilent Date: Thu, 14 Sep 2023 16:37:40 +0800 Subject: [PATCH 1/5] using viewport relative coordinate --- addons/xterm-addon-webgl/src/WebglRenderer.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/addons/xterm-addon-webgl/src/WebglRenderer.ts b/addons/xterm-addon-webgl/src/WebglRenderer.ts index 8cc81b92cd..ed416c5c8c 100644 --- a/addons/xterm-addon-webgl/src/WebglRenderer.ts +++ b/addons/xterm-addon-webgl/src/WebglRenderer.ts @@ -391,6 +391,7 @@ export class WebglRenderer extends Disposable implements IRenderer { end = clamp(end, terminal.rows - 1, 0); const cursorY = this._terminal.buffer.active.baseY + this._terminal.buffer.active.cursorY; + const viewportRelativeCursorY = cursorY - terminal.buffer.ydisp; // in case cursor.x == cols adjust visual cursor to cols - 1 const cursorX = Math.min(this._terminal.buffer.active.cursorX, terminal.cols - 1); let lastCursorX = -1; @@ -449,7 +450,7 @@ export class WebglRenderer extends Disposable implements IRenderer { if (x === cursorX) { this._model.cursor = { x: cursorX, - y: this._terminal.buffer.active.cursorY, + y: viewportRelativeCursorY, width: cell.getWidth(), style: this._coreBrowserService.isFocused ? (terminal.options.cursorStyle || 'block') : terminal.options.cursorInactiveStyle, From 27fd011e354b504998af7edb98a4f3d5d02e7b9c Mon Sep 17 00:00:00 2001 From: tisilent Date: Tue, 19 Sep 2023 20:29:28 +0800 Subject: [PATCH 2/5] Add regression tests --- test/playwright/SharedRendererTests.ts | 28 ++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/test/playwright/SharedRendererTests.ts b/test/playwright/SharedRendererTests.ts index e1e56bc948..bdfbf83a28 100644 --- a/test/playwright/SharedRendererTests.ts +++ b/test/playwright/SharedRendererTests.ts @@ -1147,6 +1147,34 @@ export function injectSharedRendererTests(ctx: ISharedRendererTestContext): void await ctx.value.proxy.selectAll(); await pollFor(ctx.value.page, () => getCellColor(ctx.value, 1, 1), [0, 0, 255, 255]); }); + test('#4799: cursor should be in the correct position', async () => { + const theme: ITheme = { + cursor: '#0000FF' + }; + await ctx.value.page.evaluate(`window.term.options.theme = ${JSON.stringify(theme)};`); + for (let index = 0; index < 160; index++) { + await ctx.value.proxy.writeln(``); + } + await ctx.value.proxy.focus(); + await ctx.value.proxy.write('\x1b[A'); + await ctx.value.proxy.write('\x1b[A'); + await ctx.value.proxy.scrollLines(-2); + await ctx.value.proxy.blur(); + await pollFor(ctx.value.page, () => getCellColor(ctx.value, 1 , 24), [0, 0, 0, 255]); + + if (frameDetails) { + const cellSize = { + width: frameDetails.decoded.width / frameDetails.cols, + height: frameDetails.decoded.height / frameDetails.rows + }; + // First point of cell + const x = Math.floor((1 - 1/* 1- to 0-based index */) * cellSize.width); + const y = Math.floor((24 - 1/* 1- to 0-based index */) * cellSize.height); + const i = (y * frameDetails.decoded.width + x) * 4/* 4 channels per pixel */; + const firstPoint = Array.from(frameDetails.decoded.data.slice(i, i + 4)) as [number, number, number, number]; + await pollFor(ctx.value.page, () => firstPoint, [0, 0, 255, 255]); + } + }); }); } From feb75a7f4d706d3b4497dab107a5a027324fcbf6 Mon Sep 17 00:00:00 2001 From: tisilent Date: Tue, 19 Sep 2023 21:58:08 +0800 Subject: [PATCH 3/5] Add getCellColorFirstPoint function --- test/playwright/SharedRendererTests.ts | 42 ++++++++++++++++---------- 1 file changed, 26 insertions(+), 16 deletions(-) diff --git a/test/playwright/SharedRendererTests.ts b/test/playwright/SharedRendererTests.ts index bdfbf83a28..fee539bd93 100644 --- a/test/playwright/SharedRendererTests.ts +++ b/test/playwright/SharedRendererTests.ts @@ -1160,35 +1160,34 @@ export function injectSharedRendererTests(ctx: ISharedRendererTestContext): void await ctx.value.proxy.write('\x1b[A'); await ctx.value.proxy.scrollLines(-2); await ctx.value.proxy.blur(); - await pollFor(ctx.value.page, () => getCellColor(ctx.value, 1 , 24), [0, 0, 0, 255]); - - if (frameDetails) { - const cellSize = { - width: frameDetails.decoded.width / frameDetails.cols, - height: frameDetails.decoded.height / frameDetails.rows - }; - // First point of cell - const x = Math.floor((1 - 1/* 1- to 0-based index */) * cellSize.width); - const y = Math.floor((24 - 1/* 1- to 0-based index */) * cellSize.height); - const i = (y * frameDetails.decoded.width + x) * 4/* 4 channels per pixel */; - const firstPoint = Array.from(frameDetails.decoded.data.slice(i, i + 4)) as [number, number, number, number]; - await pollFor(ctx.value.page, () => firstPoint, [0, 0, 255, 255]); - } + const rows = await ctx.value.proxy.rows; + await pollFor(ctx.value.page, () => getCellColor(ctx.value, 1 , rows), [0, 0, 0, 255]); + await pollFor(ctx.value.page, () => getCellColor(ctx.value ,1 , rows, CellColorPosition.FIRST), [0, 0, 255, 255]); }); }); } +enum CellColorPosition { + CENTER = 0, + FIRST = 1 +} + /** * Gets the color of the pixel in the center of a cell. * @param ctx The test context. * @param col The 1-based column index to get the color for. * @param row The 1-based row index to get the color for. */ -function getCellColor(ctx: ITestContext, col: number, row: number): MaybeAsync<[red: number, green: number, blue: number, alpha: number]> { +function getCellColor(ctx: ITestContext, col: number, row: number, position: CellColorPosition = CellColorPosition.CENTER): MaybeAsync<[red: number, green: number, blue: number, alpha: number]> { if (!frameDetails) { return getFrameDetails(ctx).then(frameDetails => getCellColorInner(frameDetails, col, row)); } - return getCellColorInner(frameDetails, col, row); + switch (position) { + case CellColorPosition.CENTER: + return getCellColorInner(frameDetails, col, row); + case CellColorPosition.FIRST: + return getCellColorFirstPoint(frameDetails, col, row); + } } let frameDetails: { cols: number, rows: number, decoded: IImage32 } | undefined = undefined; @@ -1214,6 +1213,17 @@ function getCellColorInner(frameDetails: { cols: number, rows: number, decoded: return Array.from(frameDetails.decoded.data.slice(i, i + 4)) as [number, number, number, number]; } +function getCellColorFirstPoint(frameDetails: { cols: number, rows: number, decoded: IImage32 }, col: number, row: number): [red: number, green: number, blue: number, alpha: number] { + const cellSize = { + width: frameDetails.decoded.width / frameDetails.cols, + height: frameDetails.decoded.height / frameDetails.rows + }; + const x = Math.floor((col - 1/* 1- to 0-based index */) * cellSize.width); + const y = Math.floor((row - 1/* 1- to 0-based index */) * cellSize.height); + const i = (y * frameDetails.decoded.width + x) * 4/* 4 channels per pixel */; + return Array.from(frameDetails.decoded.data.slice(i, i + 4)) as [number, number, number, number]; +} + const COLORS_16_TO_255 = [ '#000000', '#00005f', '#000087', '#0000af', '#0000d7', '#0000ff', '#005f00', '#005f5f', '#005f87', '#005faf', '#005fd7', '#005fff', '#008700', '#00875f', '#008787', '#0087af', '#0087d7', '#0087ff', '#00af00', '#00af5f', '#00af87', '#00afaf', '#00afd7', '#00afff', '#00d700', '#00d75f', '#00d787', '#00d7af', '#00d7d7', '#00d7ff', '#00ff00', '#00ff5f', From a8ef1d49a112576d0b240c17c8c3fcb27f97bc9e Mon Sep 17 00:00:00 2001 From: tisilent Date: Tue, 19 Sep 2023 22:15:35 +0800 Subject: [PATCH 4/5] Add block cursor style confirmation --- test/playwright/SharedRendererTests.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/test/playwright/SharedRendererTests.ts b/test/playwright/SharedRendererTests.ts index fee539bd93..1fe673515e 100644 --- a/test/playwright/SharedRendererTests.ts +++ b/test/playwright/SharedRendererTests.ts @@ -1159,10 +1159,13 @@ export function injectSharedRendererTests(ctx: ISharedRendererTestContext): void await ctx.value.proxy.write('\x1b[A'); await ctx.value.proxy.write('\x1b[A'); await ctx.value.proxy.scrollLines(-2); - await ctx.value.proxy.blur(); const rows = await ctx.value.proxy.rows; - await pollFor(ctx.value.page, () => getCellColor(ctx.value, 1 , rows), [0, 0, 0, 255]); - await pollFor(ctx.value.page, () => getCellColor(ctx.value ,1 , rows, CellColorPosition.FIRST), [0, 0, 255, 255]); + // block cursor style + await pollFor(ctx.value.page, () => getCellColor(ctx.value, 1, rows), [0, 0, 0, 255]); + await ctx.value.proxy.blur(); + // other cursor style + await pollFor(ctx.value.page, () => getCellColor(ctx.value, 1, rows), [0, 0, 0, 255]); + await pollFor(ctx.value.page, () => getCellColor(ctx.value, 1, rows, CellColorPosition.FIRST), [0, 0, 255, 255]); }); }); } From da2687174f7fea5d7512f6118caf64d6edf7fea9 Mon Sep 17 00:00:00 2001 From: tisilent Date: Tue, 19 Sep 2023 22:49:53 +0800 Subject: [PATCH 5/5] :lipstick: --- test/playwright/SharedRendererTests.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test/playwright/SharedRendererTests.ts b/test/playwright/SharedRendererTests.ts index 1fe673515e..3911f0c0b7 100644 --- a/test/playwright/SharedRendererTests.ts +++ b/test/playwright/SharedRendererTests.ts @@ -1161,9 +1161,10 @@ export function injectSharedRendererTests(ctx: ISharedRendererTestContext): void await ctx.value.proxy.scrollLines(-2); const rows = await ctx.value.proxy.rows; // block cursor style - await pollFor(ctx.value.page, () => getCellColor(ctx.value, 1, rows), [0, 0, 0, 255]); + await pollFor(ctx.value.page, () => getCellColor(ctx.value, 1, rows), [0, 0, 255, 255]); await ctx.value.proxy.blur(); - // other cursor style + frameDetails = undefined; + // outlink cursor style await pollFor(ctx.value.page, () => getCellColor(ctx.value, 1, rows), [0, 0, 0, 255]); await pollFor(ctx.value.page, () => getCellColor(ctx.value, 1, rows, CellColorPosition.FIRST), [0, 0, 255, 255]); });