mapbox-gl-js icon indicating copy to clipboard operation
mapbox-gl-js copied to clipboard

Workaround unexpected terrain spikes in browsers with fingerprint protection enabled

Open astojilj opened this issue 2 years ago • 12 comments

The v3 migration guide Known issues and limitations refers to an issue with spikes visible on terrain when run in Safari 17 private browsing mode (edit: and Firefox with fingerprint protection enabled):

In Safari 17 private browsing mode, Apple's Advanced Privacy Protection introduces noise into key fingerprinting areas like 2D Canvas and WebGL and may cause unexpected terrain spikes in GL JS v3.

The issue also exists with previous GL JS versions.

While we're working on resolving this, a feasible workaround would be to disable terrain from the application code, when it is detected that anti-fingerprinting protection introduces noise to 2D canvas operations:

export function isPrivateModeSafariWithCanvasFingerprintProtection(scope: any): boolean {
    if (!isSafari(scope)) return false;
    // Starting from version 17, fingerprinting protection introduces fuzz to Canvas2D operations used for image decoding.
    const version = scope.navigator ? scope.navigator.userAgent.match(/Version\/([0-9\._]+).*Safari/) : [];
    if (!(version.length === 2 && parseInt(version[1]) >= 17)) {
        return false;
    }
    assert(window.OffscreenCanvas);
    const offscreenCanvas = new window.OffscreenCanvas(255 / 3, 1);
    const offscreenCanvasContext = offscreenCanvas.getContext('2d', {willReadFrequently: true});
    let inc = 0;
    // getImageData is lossy with premultiplied alpha.
    for (let i = 0; i < offscreenCanvas.width; ++i) {
        offscreenCanvasContext.fillStyle = `rgba(${inc++},${inc++},${inc++}, 255)`;
        offscreenCanvasContext.fillRect(i, 0, 1, 1);
    }
    const readData = offscreenCanvasContext.getImageData(0, 0, offscreenCanvas.width, offscreenCanvas.height);
    inc = 0;
    for (let i = 0; i < readData.data.length; ++i) {
        if (i % 4 !== 3) {
            if (inc++ !== readData.data[i]) {
                return true;
            }
        }
    }
    return false;
}

image

astojilj avatar Dec 04 '23 10:12 astojilj

Same here with Firefox 121.0.1 64bit on Mac OS, with every version of old Mapbox GL JS maps i tried, IMHO a issue with the changed renderer, not with Mapbox.

CptHolzschnauz avatar Jan 15 '24 05:01 CptHolzschnauz

We'll ship this workaround along with the v3.1 release.

stepankuzmin avatar Jan 16 '24 15:01 stepankuzmin

@stepankuzmin Seeing a visually different, but probably related rendering bug only in Safari private mode and Brave. The issue appears with both v3.1.0 and v3.2.0.

Here's a minimal codepen based on the globe example from the docs. Just the map style was replaced with one where 3D terrain is enabled: https://codepen.io/slavanga/pen/eYovgLg

Bildschirmfoto 2024-03-20 um 17 37 03

Rendering with the default monochrome style, just 3D terrain enabled:

Bildschirmfoto 2024-03-20 um 17 38 18

Video of the same:

https://github.com/mapbox/mapbox-gl-js/assets/1077807/caba5574-a6c2-4b96-b289-70d522fb5db1

Rendering with a more customized map style:

Bildschirmfoto 2024-03-20 um 17 26 55

slavanga avatar Mar 20 '24 16:03 slavanga

Also seeing the same thing as @slavanga on firefox 124.0.1 Windows Screenshot 2024-03-22 180556

calb-dev avatar Mar 22 '24 18:03 calb-dev

Hi @slavanga and @calb-dev,

Thanks for flagging this, I confirm this is still an issue. The fix for the workaround is coming in v3.3.0.

stepankuzmin avatar Apr 02 '24 15:04 stepankuzmin

It seems the workaround disables terrain when configured in a style, but not for map.setTarrain. For example, this still displays with noisy terrain:

https://docs.mapbox.com/mapbox-gl-js/example/add-terrain/

Can you recommend a similar workaround for disabling hillshade? It also has the noise issue here:

https://docs.mapbox.com/mapbox-gl-js/example/hillshade/

Maybe make use of hasCanvasFingerprintNoise() in src/util/browser.ts?

elygeo avatar Jun 30 '24 18:06 elygeo

The issue is back with 3.5.1 in Firefox: Bildschirmfoto 2024-07-05 um 16 35 06

While in 3.4 the problem was solved:

Bildschirmfoto 2024-07-05 um 16 38 43

CptHolzschnauz avatar Jul 05 '24 14:07 CptHolzschnauz

Thanks for flagging this again. The fix for the workaround is coming in v3.5.2.

stepankuzmin avatar Jul 17 '24 14:07 stepankuzmin

Issue is still present with 3.52 when just adding a layer of type symbol. Even worse with Safari on iOS (Screenshot below). IMHO this makes MapBox unusable for PWAs. Error is not occuring with MapBox 3.4 or MapLibre. IMG_8925

CptHolzschnauz avatar Jul 20 '24 05:07 CptHolzschnauz

Yeah, I can reproduce it now, good catch @CptHolzschnauz. We'll fix that in the next release.

stepankuzmin avatar Jul 23 '24 12:07 stepankuzmin

Thx. Let me know if I can help you with providing informations. My experience is that sometimes the bug occurs right from the initial render and sometimes you have to zoom out until it starts and getting worse until mapbox JS crashes.

CptHolzschnauz avatar Jul 23 '24 12:07 CptHolzschnauz

It's occuring when tilting, see the video below. iOS 17.5.1 with Safari.

https://github.com/user-attachments/assets/d82129f7-5c86-4a50-8507-45f53bfc4bff

CptHolzschnauz avatar Jul 23 '24 19:07 CptHolzschnauz