microsoft / vscode

Visual Studio Code
https://code.visualstudio.com
MIT License
163.99k stars 29.19k forks source link

window.innerHeight is way larger than the actual window height on macOS #225808

Open flekschas opened 2 months ago

flekschas commented 2 months ago

Type: Bug

  1. First install ipykernel and anywidget (!pip install anywidget)
  2. Create a notebook file test.ipynb
  3. Create the following widget and inspect the console.log statement
import anywidget

class CanvasWidget(anywidget.AnyWidget):
    _esm = """
    function render({ model, el }) {
      const canvas = document.createElement("canvas");

      const resize = () => {
        canvas.height = window.innerHeight * window.devicePixelRatio;
        canvas.width = window.innerWidth * window.devicePixelRatio;
        console.log(`Canvas size is ${canvas.width} (w) x ${canvas.height} (h)`);
      }

      window.addEventListener('resize', resize);

      el.appendChild(canvas);
    }
    export default { render };
    """

CanvasWidget()

In my case the reported canvas size is 1940 (w) x 33554426 (h). While the width is correct the height is complete out of bounds! I don't think there exists a monitor with a 33 million pixels tall display panel.

When I manual get the window.innerHeight, window.innerWidth, window.devicePixelRatio in the web console, the values are 1091, 1118 , and 2.

Screenshot 2024-08-16 at 3 21 39 PM

Where is the incorrect height of 33554426 coming from?! And is there a way around this?

tl/dr I'm the developer of a widget that relies on the window size to determine the appropriate size for a full-sized canvas element. However, the incorrect height of 33554426 is causing the widget to break because no GPU can work with a texture that large (which is what ultimately happens in the widget)

VS Code version: Code 1.92.2 (Universal) (fee1edb8d6d72a0ddff41e5f71a671c23ed924b9, 2024-08-14T17:29:30.058Z) OS version: Darwin arm64 23.2.0 Modes:

System Info |Item|Value| |---|---| |CPUs|Apple M1 Max (10 x 2400)| |GPU Status|2d_canvas: enabled
canvas_oop_rasterization: enabled_on
direct_rendering_display_compositor: disabled_off_ok
gpu_compositing: enabled
multiple_raster_threads: enabled_on
opengl: enabled_on
rasterization: enabled
raw_draw: disabled_off_ok
skia_graphite: disabled_off
video_decode: enabled
video_encode: enabled
webgl: enabled
webgl2: enabled
webgpu: enabled
webnn: disabled_off| |Load (avg)|4, 6, 8| |Memory (System)|32.00GB (0.71GB free)| |Process Argv|| |Screen Reader|no| |VM|0%|
Extensions (15) Extension|Author (truncated)|Version ---|---|--- vscode-eslint|dba|3.0.10 gitlens|eam|15.3.0 EditorConfig|Edi|0.16.4 vsc-material-theme|Equ|2.4.2 debugpy|ms-|2024.10.0 isort|ms-|2023.10.1 python|ms-|2024.12.3 vscode-pylance|ms-|2024.8.1 jupyter|ms-|2024.7.0 jupyter-keymap|ms-|1.1.2 jupyter-renderers|ms-|1.0.19 vscode-jupyter-cell-tags|ms-|0.1.9 vscode-jupyter-slideshow|ms-|0.1.6 cpptools|ms-|1.21.6 sublime-keybindings|ms-|4.1.10 (1 theme extensions excluded)
flekschas commented 2 months ago

It appears as if the issue that the widget does not have access to the actual window object since it's instantiated in an isolated iframe within an isolated iframe.

In that context it might be impossible to directly access the real window's inner height. I tried to use top.innerWidth and top.innerHeight but the origin policy of the vscode-webview frame seems to forbid reading those values. Is there any other way a widget developer can get the height of the VSCode window?

I noticed that the window.innerHeight is also in conflict with window.screen.availHeight property, which is 1271 in the above example. Is this intended behavior?

rebornix commented 1 month ago

@flekschas thanks for providing detailed info of how you are rendering the output.

In my case the reported canvas size is 1940 (w) x 33554426 (h). While the width is correct the height is complete out of bounds! I don't think there exists a monitor with a 33 million pixels tall display panel

As you noticed, the outputs are rendered inside iframe inside vscode-webview/iframes, which isolates arbitrary code from VS Code's renderer process (where we render the workbench). The webview itself is much larger than the viewport, and the output containers are absolutely positioned inside the webview. The advantage of it when you scroll the notebook, all we need to do is updating the webview element's top/scrolltop.

The catch of this design is the innerHeight is no longer the same as the viewport height. window.screen.availHeight is the better alternative.

rebornix commented 1 month ago

and thank you @flekschas for providing the ultimate solution window.screen.availHeight, we should document this for output renderers.