mapbox / mapbox/mapbox-gl-js

Workaround unexpected terrain spikes in browsers with fingerprint protection enabled

Open
#12,997 12 comments 0 reactions 1 assignee View on GitHub

@astojilj is already working on this.

Since Dec 4, 2023.

bug :lady_beetle: environment-specific :desktop_computer:
Dominant language
TypeScript
Stars
12.4k
Forks
2.4k
PR merge metrics
No merged PRs in 30d

Description

The v3 migration guide [Known issues and limitations](https://docs.mapbox.com/mapbox-gl-js/guides/migrate-to-v3/#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](https://developer.apple.com/documentation/safari-release-notes/safari-17-release-notes#Private-Browsing) 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:

```js
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](https://github.com/mapbox/mapbox-gl-js/assets/25395/1550c81e-be35-46f0-9880-daf0acac6e96)

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.