diff options
-rw-r--r-- | browser/src/layer/tile/CanvasSectionContainer.ts | 16 | ||||
-rw-r--r-- | browser/src/layer/tile/CanvasTileLayer.js | 53 |
2 files changed, 55 insertions, 14 deletions
diff --git a/browser/src/layer/tile/CanvasSectionContainer.ts b/browser/src/layer/tile/CanvasSectionContainer.ts index 61c78f7de4..396d48fc0a 100644 --- a/browser/src/layer/tile/CanvasSectionContainer.ts +++ b/browser/src/layer/tile/CanvasSectionContainer.ts @@ -1510,6 +1510,22 @@ class CanvasSectionContainer { this.canvas.width = newWidth; this.canvas.height = newHeight; + // Partial fix for #5876 reduce size if canvas context is null + // WKWebView has a hard limit on the number of bytes of canvas + // context memory that can be allocated. Canvas with sizes that + // are too large will return a null context so reduce the size + // of the canvas until a non-null context is obtained. + if ((window as any).ThisIsTheiOSApp) { + this.context = this.canvas.getContext('2d', { alpha: false }); + while (!this.context && this.canvas.width >= 2 && this.canvas.height >= 2) { + this.canvas.width /= 2; + this.canvas.height /= 2; + this.context = this.canvas.getContext('2d', { alpha: false }); + } + for (var i: number = 0; i < this.sections.length; i++) + this.sections[i].context = this.context; + } + // CSS pixels can be fractional, but need to round to the same real pixels var cssWidth: number = newWidth / app.dpiScale; // NB. beware var cssHeight: number = newHeight / app.dpiScale; diff --git a/browser/src/layer/tile/CanvasTileLayer.js b/browser/src/layer/tile/CanvasTileLayer.js index a6b4c209f4..498df2a33b 100644 --- a/browser/src/layer/tile/CanvasTileLayer.js +++ b/browser/src/layer/tile/CanvasTileLayer.js @@ -6619,6 +6619,19 @@ L.CanvasTileLayer = L.Layer.extend({ return new L.LatLngBounds(nw, se); }, + _reclaimTileCanvasMemory: function (tile) { + // Partial fix for #5876 allow immediate reuse of canvas context memory + // WKWebView has a hard limit on the number of bytes of canvas + // context memory that can be allocated. Reducing the canvas + // size to zero is a way to reduce the number of bytes counted + // against this limit. + if (window.ThisIsTheiOSApp && tile && tile.el && tile.el instanceof HTMLCanvasElement) { + tile.el.width = 0; + tile.el.height = 0; + delete tile.el; + } + }, + _removeTile: function (key) { var tile = this._tiles[key]; if (!tile) { return; } @@ -6712,6 +6725,32 @@ L.CanvasTileLayer = L.Layer.extend({ var imgData; var ctx = canvas.getContext('2d'); + // Partial fix for issue #5876 discard excess canvas contexts + // WKWebView has a hardcoded memory limit for all canvas contexts + // so if canvas.getContext('2d') returns null, convert the canvas + // of other tiles to an image until canvas.getContext('2d') succeeds. + if (!ctx && window.ThisIsTheiOSApp) { + for (var key in this._tiles) { + var value = this._tiles[key]; + if (value && value !== tile && value.el && value.el instanceof HTMLCanvasElement) { + var imageSrc = value.el.toDataURL(); + this._reclaimTileCanvasMemory(value); + value.el = document.createElement('img'); + value.el.src = imageSrc; + if (!(value._invalidCount > 0) && this._tileCache[key]) + this._tileCache[key] = value.el; + ctx = canvas.getContext('2d'); + if (ctx) + break; + } + } + + // If we can't free up enough canvas context, there is nothing + // more we can do. Is there a better way to handle this? + if (!ctx) + return; + } + while (offset < allDeltas.length) { if (this._debugDeltas) @@ -6768,20 +6807,6 @@ L.CanvasTileLayer = L.Layer.extend({ if (imgData) ctx.putImageData(imgData, 0, 0); - // Partial fix for issue #5876 discard canvas contexts immediately - // WKWebView has a hardcoded memory limit for all canvas contexts - // so immediately convert the canvas to an image and release the - // canvas context's backing store. - // This bug only appears in the iOS app because most .png tiles are - // passed as raw data, not as "data:" strings, in the iOS app. - if (window.ThisIsTheiOSApp) { - tile.el = document.createElement('img'); - tile.el.src = canvas.toDataURL(); - canvas.width = 0; - canvas.height = 0; - canvas = null; - } - if (traceEvent) traceEvent.finish(); }, |