Monaco-editor: Expose API to remeasure character widths (drop the cache) such that lazy loaded fonts can have correct sizes

Created on 13 Mar 2017  路  6Comments  路  Source: microsoft/monaco-editor

monaco-editor version: 0.8.2
Browser: Chrome 55
OS: Windows 7

Create editor with fontFamily: '"Source-Code-Pro", "Courier New", monospace'.
Clicking in the editor will result in the cursor being misaligned with the rendered text.
Removing the custom font fixes the issue.

api feature-request

Most helpful comment

My testing showed that the cause was the age old problem of the custom fonts not being loaded before JavaScript code tries to measure them.

In my app this was usually seen when the page was browsed with a cold browser cache (or with dev tools open and Disable cache option enabled).

My simple workaround:

function isFontLoaded() {
    const e1 = document.createElement("span");
    e1.style.fontFamily = "Inconsolata, sans-serif";
    const e2 = document.createElement("span");
    e2.style.fontFamily = "sans-serif";

    e1.innerHTML = e2.innerHTML = "|";

    const body = document.body;
    body.appendChild(e1);
    body.appendChild(e2);

    const result = e1.offsetWidth !== e2.offsetWidth;

    body.removeChild(e1);
    body.removeChild(e2);
    return result;
}

function startEditor() {
    let fontFamily = "Consolas, Monaco, 'Courier New', monospace";

    if (!isFontLoaded()) {
        if (performance.now && performance.now() < 3000) {
            // delay for up to 3 secs after page load
            window.setTimeout(startEditor, 500);
            return;
        }
    } else {
        fontFamily = "Inconsolata, " + fontFamily;
    }

    require(['vs/editor/editor.main'], () => {
        ....
    }
}

All 6 comments

simple recreate: setting default font option to bold

it would seem that this occurs if there is a parent style with css letter-spacing: normal; - without that (or using unset) misc. fonts works fine in 0.8.3

My testing showed that the cause was the age old problem of the custom fonts not being loaded before JavaScript code tries to measure them.

In my app this was usually seen when the page was browsed with a cold browser cache (or with dev tools open and Disable cache option enabled).

My simple workaround:

function isFontLoaded() {
    const e1 = document.createElement("span");
    e1.style.fontFamily = "Inconsolata, sans-serif";
    const e2 = document.createElement("span");
    e2.style.fontFamily = "sans-serif";

    e1.innerHTML = e2.innerHTML = "|";

    const body = document.body;
    body.appendChild(e1);
    body.appendChild(e2);

    const result = e1.offsetWidth !== e2.offsetWidth;

    body.removeChild(e1);
    body.removeChild(e2);
    return result;
}

function startEditor() {
    let fontFamily = "Consolas, Monaco, 'Courier New', monospace";

    if (!isFontLoaded()) {
        if (performance.now && performance.now() < 3000) {
            // delay for up to 3 secs after page load
            window.setTimeout(startEditor, 500);
            return;
        }
    } else {
        fontFamily = "Inconsolata, " + fontFamily;
    }

    require(['vs/editor/editor.main'], () => {
        ....
    }
}

Perhaps we should expose API to re-measure (drop the font measurement cache).

CSS Font Loading API can notify when all fonts are loaded.

const callback = () => {
    console.log("All fonts are loaded.")
}
document.fonts.ready.then(callback)

Or check if one font is loaded:

const isFontReady = document.fonts.check('1em Fira Code'))

Unfortunately IE/Edge does not support it. :(

For cross-browser support there is Font Face Observer:

const font = new FontFaceObserver("Fira Code")
font.load().then(callback, (e) => {
    console.error("Could not load the font")
})

We're wondering if there are workarounds to invalidate the cache, or the scope of the work to implement this feature.

We're seeing that on some devices when the device is attached to an external display and the display scale changes that the font cache measurements may become stale.

Ideally we'd be able to call this API when the devicePixelRatio changes.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

inf9144 picture inf9144  路  3Comments

Spongman picture Spongman  路  3Comments

andreymarchenko picture andreymarchenko  路  3Comments

galyech picture galyech  路  3Comments

chengtie picture chengtie  路  3Comments