summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPatrick Luby <plubius@neooffice.org>2023-05-15 16:03:35 -0400
committerPatrick Luby <plubius@neooffice.org>2023-05-15 18:28:02 -0400
commita9b5abfc51960cfcb18aff295d89b7327c43bf7e (patch)
tree848153b509369c61df2e598637cb3596848f6b3b
parentFix debug build breakage due to undefined function on iOS (diff)
downloadonline-ioscanvasmemory2205.tar.gz
online-ioscanvasmemory2205.zip
Partial fix for issue #5876 handle null canvas contexts in iOS app ioscanvasmemory2205iosbuildbreakages2205
WKWebView has hard limits on both the number of pixels and the number of bytes of canvas context memory that can be allocated so try to handle such cases when the occur. This fix is limited only to the iOS app because there were reports of unexpected slowness to redraw in Collabora Online. But this fix is needed in the iOS app because if a canvas context is null, CPU usage will spike when in a lengthy PDF file and the iOS app will become unusable until the app is killed and restarted. For me, the unexpected slowness to redraw appears when clicking on a cell touching the freeze line in a Calc document after doing the steps in the following post: https://github.com/CollaboraOnline/online/pull/6218#pullrequestreview-1425542844 The unexpected slowness to redraw appears to be caused by commit 7454fbe182f9171533ffd058a494f2d6218e3bb3 that was reverted. Fortunately, the tile reclaiming when a canvas context is null does not appear to be the cause since it is what is needed to fix issue #5876. The problem that I saw was cuased by all of the other calls to _reclaimTileCanvasMemory() whenever a tile was removed from a list. Apparently this is too soon to reclaim canvas memory in some cases so those calls are not included in this change. Signed-off-by: Patrick Luby <plubius@neooffice.org> Change-Id: Ib393b80dbf5063016545dac0f0b18cc18ef6c182
-rw-r--r--browser/src/layer/tile/CanvasSectionContainer.ts16
-rw-r--r--browser/src/layer/tile/CanvasTileLayer.js53
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();
},