Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Request output rendering when idle in webview. #176710

Merged
merged 2 commits into from Mar 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -869,7 +869,7 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD

if (!activeWebview.insetMapping.has(output.source)) {
const cellTop = this._list.getAbsoluteTopOfElement(cellDiffViewModel);
await activeWebview.createOutput({ diffElement: cellDiffViewModel, cellHandle: cellViewModel.handle, cellId: cellViewModel.id, cellUri: cellViewModel.uri }, output, cellTop, getOffset(), false);
await activeWebview.createOutput({ diffElement: cellDiffViewModel, cellHandle: cellViewModel.handle, cellId: cellViewModel.id, cellUri: cellViewModel.uri }, output, cellTop, getOffset());
} else {
const cellTop = this._list.getAbsoluteTopOfElement(cellDiffViewModel);
const outputIndex = cellViewModel.outputsViewModels.indexOf(output.source);
Expand Down
Expand Up @@ -2664,13 +2664,17 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditorD
if (!existingOutput
|| (!existingOutput.renderer && output.type === RenderOutputType.Extension)
) {
this._webview.createOutput({ cellId: cell.id, cellHandle: cell.handle, cellUri: cell.uri, executionId: cell.internalMetadata.executionId }, output, cellTop, offset, createWhenIdle);
if (createWhenIdle) {
this._webview.requestCreateOutputWhenWebviewIdle({ cellId: cell.id, cellHandle: cell.handle, cellUri: cell.uri, executionId: cell.internalMetadata.executionId }, output, cellTop, offset);
} else {
this._webview.createOutput({ cellId: cell.id, cellHandle: cell.handle, cellUri: cell.uri, executionId: cell.internalMetadata.executionId }, output, cellTop, offset);
}
} else if (existingOutput.renderer
&& output.type === RenderOutputType.Extension
&& existingOutput.renderer.id !== output.renderer.id) {
// switch mimetype
this._webview.removeInsets([output.source]);
this._webview.createOutput({ cellId: cell.id, cellHandle: cell.handle, cellUri: cell.uri }, output, cellTop, offset, createWhenIdle);
this._webview.createOutput({ cellId: cell.id, cellHandle: cell.handle, cellUri: cell.uri }, output, cellTop, offset);
} else {
const outputIndex = cell.outputsViewModels.indexOf(output.source);
const outputOffset = cell.getOutputOffset(outputIndex);
Expand Down
Expand Up @@ -6,7 +6,7 @@
import * as osPath from 'vs/base/common/path';
import { IMouseWheelEvent } from 'vs/base/browser/mouseEvent';
import { coalesce } from 'vs/base/common/arrays';
import { DeferredPromise, runWhenIdle } from 'vs/base/common/async';
import { DeferredPromise } from 'vs/base/common/async';
import { decodeBase64 } from 'vs/base/common/buffer';
import { Emitter, Event } from 'vs/base/common/event';
import { getExtensionForMimeType } from 'vs/base/common/mime';
Expand Down Expand Up @@ -126,6 +126,9 @@ export class BackLayerWebView<T extends ICommonCellInfo> extends Themable {
element: HTMLElement;
webview: IWebviewElement | undefined = undefined;
insetMapping: Map<IDisplayOutputViewModel, ICachedInset<T>> = new Map();
pendingWebviewIdleInsetCreationRequest: Map<IDisplayOutputViewModel, ICachedInset<T>> = new Map();
private reversedPendingWebviewIdleInsetMapping: Map<string, IDisplayOutputViewModel> = new Map();

pendingInsetCreationRequest: Map<IDisplayOutputViewModel, IDisposable> = new Map();
readonly markupPreviewMapping = new Map<string, IMarkupCellInitialization>();
private hiddenInsetMapping: Set<IDisplayOutputViewModel> = new Set();
Expand Down Expand Up @@ -579,6 +582,17 @@ export class BackLayerWebView<T extends ICommonCellInfo> extends Themable {
const { cellInfo, output } = resolvedResult;
this.notebookEditor.updateOutputHeight(cellInfo, output, height, !!update.init, 'webview#dimension');
this.notebookEditor.scheduleOutputHeightAck(cellInfo, update.id, height);
} else if (update.init) {
// might be idle render request's ack
const outputRequest = this.reversedPendingWebviewIdleInsetMapping.get(update.id);
if (outputRequest) {
const inset = this.pendingWebviewIdleInsetCreationRequest.get(outputRequest)!;
const cellInfo = inset.cellInfo;
this.reversedInsetMapping.set(update.id, outputRequest);
this.insetMapping.set(outputRequest, inset);
this.notebookEditor.updateOutputHeight(cellInfo, outputRequest, height, !!update.init, 'webview#dimension');
this.notebookEditor.scheduleOutputHeightAck(cellInfo, update.id, height);
}
}
} else {
this.notebookEditor.updateMarkupCellHeight(update.id, height, !!update.init);
Expand Down Expand Up @@ -1279,13 +1293,38 @@ export class BackLayerWebView<T extends ICommonCellInfo> extends Themable {
}
}

createOutput(cellInfo: T, content: IInsetRenderOutput, cellTop: number, offset: number, createWhenIdle: boolean): void {
requestCreateOutputWhenWebviewIdle(cellInfo: T, content: IInsetRenderOutput, cellTop: number, offset: number) {
if (this._disposed) {
return;
}

if (this.insetMapping.has(content.source)) {
return;
}

if (this.pendingWebviewIdleInsetCreationRequest.has(content.source)) {
return;
}

const { message, renderer } = this._createOutputCreationMessage(cellInfo, content, cellTop, offset, true, true);
this._sendMessageToWebview(message);
this.pendingWebviewIdleInsetCreationRequest.set(content.source, { outputId: message.outputId, cellInfo: cellInfo, renderer, cachedCreation: message });
this.reversedPendingWebviewIdleInsetMapping.set(message.outputId, content.source);
}

createOutput(cellInfo: T, content: IInsetRenderOutput, cellTop: number, offset: number): void {
if (this._disposed) {
return;
}

const cachedInset = this.insetMapping.get(content.source);

// we now request to render the output immediately, so we can remove the pending request
this.pendingWebviewIdleInsetCreationRequest.delete(content.source);
if (cachedInset) {
this.reversedPendingWebviewIdleInsetMapping.delete(cachedInset.outputId);
}

if (cachedInset && this._cachedInsetEqual(cachedInset, content)) {
this.hiddenInsetMapping.delete(content.source);
this._sendMessageToWebview({
Expand All @@ -1300,70 +1339,70 @@ export class BackLayerWebView<T extends ICommonCellInfo> extends Themable {

// create new output
const createOutput = () => {
const messageBase = {
type: 'html',
executionId: cellInfo.executionId,
cellId: cellInfo.cellId,
cellTop: cellTop,
outputOffset: offset,
left: 0,
requiredPreloads: [],
} as const;

let message: ICreationRequestMessage;
let renderer: INotebookRendererInfo | undefined;
if (content.type === RenderOutputType.Extension) {
const output = content.source.model;
renderer = content.renderer;
const first = output.outputs.find(op => op.mime === content.mimeType)!;

// TODO@jrieken - the message can contain "bytes" and those are transferable
// which improves IPC performance and therefore should be used. However, it does
// means that the bytes cannot be used here anymore
message = {
...messageBase,
outputId: output.outputId,
rendererId: content.renderer.id,
content: {
type: RenderOutputType.Extension,
outputId: output.outputId,
metadata: output.metadata,
output: {
mime: first.mime,
valueBytes: first.data.buffer,
},
allOutputs: output.outputs.map(output => ({ mime: output.mime })),
},
};
} else {
message = {
...messageBase,
outputId: UUID.generateUuid(),
content: {
type: content.type,
htmlContent: content.htmlContent,
}
};
}

const { message, renderer } = this._createOutputCreationMessage(cellInfo, content, cellTop, offset, false, false);
this._sendMessageToWebview(message);
this.insetMapping.set(content.source, { outputId: message.outputId, cellInfo: cellInfo, renderer, cachedCreation: message });
this.hiddenInsetMapping.delete(content.source);
this.reversedInsetMapping.set(message.outputId, content.source);
};

if (createWhenIdle) {
this.pendingInsetCreationRequest.get(content.source)?.dispose();
this.pendingInsetCreationRequest.set(content.source, runWhenIdle(() => {
createOutput();
this.pendingInsetCreationRequest.delete(content.source);
}));
createOutput();
}

private _createOutputCreationMessage(cellInfo: T, content: IInsetRenderOutput, cellTop: number, offset: number, createOnIdle: boolean, initiallyHidden: boolean): { readonly message: ICreationRequestMessage; readonly renderer: INotebookRendererInfo | undefined } {
const messageBase = {
type: 'html',
executionId: cellInfo.executionId,
cellId: cellInfo.cellId,
cellTop: cellTop,
outputOffset: offset,
left: 0,
requiredPreloads: [],
createOnIdle: createOnIdle
} as const;

let message: ICreationRequestMessage;
let renderer: INotebookRendererInfo | undefined;
if (content.type === RenderOutputType.Extension) {
const output = content.source.model;
renderer = content.renderer;
const first = output.outputs.find(op => op.mime === content.mimeType)!;

// TODO@jrieken - the message can contain "bytes" and those are transferable
// which improves IPC performance and therefore should be used. However, it does
// means that the bytes cannot be used here anymore
message = {
...messageBase,
outputId: output.outputId,
rendererId: content.renderer.id,
content: {
type: RenderOutputType.Extension,
outputId: output.outputId,
metadata: output.metadata,
output: {
mime: first.mime,
valueBytes: first.data.buffer,
},
allOutputs: output.outputs.map(output => ({ mime: output.mime })),
},
initiallyHidden: initiallyHidden
};
} else {
this.pendingInsetCreationRequest.get(content.source)?.dispose();
this.pendingInsetCreationRequest.delete(content.source);
createOutput();
message = {
...messageBase,
outputId: UUID.generateUuid(),
content: {
type: content.type,
htmlContent: content.htmlContent,
},
initiallyHidden: initiallyHidden
};
}

return {
message,
renderer
};
}

updateOutput(cellInfo: T, content: IInsetRenderOutput, cellTop: number, offset: number): void {
Expand All @@ -1372,7 +1411,7 @@ export class BackLayerWebView<T extends ICommonCellInfo> extends Themable {
}

if (!this.insetMapping.has(content.source)) {
this.createOutput(cellInfo, content, cellTop, offset, false);
this.createOutput(cellInfo, content, cellTop, offset);
return;
}

Expand Down
Expand Up @@ -201,6 +201,7 @@ export interface ICreationRequestMessage {
readonly initiallyHidden?: boolean;
readonly rendererId?: string | undefined;
readonly executionId?: string | undefined;
readonly createOnIdle: boolean;
}

export interface IContentWidgetTopRequest {
Expand Down