[canvaskit] reuse canvases when window resizes (#22966)

This commit is contained in:
Yegor 2020-12-11 15:05:11 -08:00 committed by GitHub
parent 54aaac815f
commit 3cdb6de239
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 74 additions and 3 deletions

View File

@ -96,19 +96,31 @@ class Surface {
throw CanvasKitError('Cannot create surfaces of empty size.');
}
if (size == _currentSize) {
// Check if the window is shrinking in size, and if so, don't allocate a
// new canvas as the previous canvas is big enough to fit everything.
final ui.Size? previousSize = _currentSize;
if (previousSize != null &&
size.width <= previousSize.width &&
size.height <= previousSize.height) {
// The existing surface is still reusable.
return;
}
_currentSize = size;
_currentSize = _currentSize == null
// First frame. Allocate a canvas of the exact size as the window. The
// window is frequently never resized, particularly on mobile, so using
// the exact size is most optimal.
? size
// The window is growing. Overallocate to prevent frequent reallocations.
: size * 1.4;
_surface?.dispose();
_surface = null;
htmlElement?.remove();
htmlElement = null;
_addedToScene = false;
_surface = _wrapHtmlCanvas(size);
_surface = _wrapHtmlCanvas(_currentSize!);
}
CkSurface _wrapHtmlCanvas(ui.Size physicalSize) {

View File

@ -0,0 +1,59 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.12
import 'package:test/bootstrap/browser.dart';
import 'package:test/test.dart';
import 'package:ui/src/engine.dart';
import 'package:ui/ui.dart' as ui;
import 'common.dart';
void main() {
internalBootstrapBrowserTest(() => testMain);
}
void testMain() {
group('CanvasKit', () {
setUpCanvasKitTest();
test('Surface allocates canvases efficiently', () {
final Surface surface = Surface(HtmlViewEmbedder());
final CkSurface original = surface.acquireRenderSurface(ui.Size(9, 19));
// Expect exact requested dimensions.
expect(original.width(), 9);
expect(original.height(), 19);
// Shrinking reuses the existing surface straight-up.
final CkSurface shrunk = surface.acquireRenderSurface(ui.Size(5, 15));
expect(shrunk, same(original));
// The first increase will allocate a new surface, but will overallocate
// by 40% to accommodate future increases.
final CkSurface firstIncrease = surface.acquireRenderSurface(ui.Size(10, 20));
expect(firstIncrease, isNot(same(original)));
// Expect overallocated dimensions
expect(firstIncrease.width(), 14);
expect(firstIncrease.height(), 28);
// Subsequent increases within 40% reuse the old surface.
final CkSurface secondIncrease = surface.acquireRenderSurface(ui.Size(11, 22));
expect(secondIncrease, same(firstIncrease));
// Increases beyond the 40% limit will cause a new allocation.
final CkSurface huge = surface.acquireRenderSurface(ui.Size(20, 40));
expect(huge, isNot(same(firstIncrease)));
// Also over-allocated
expect(huge.width(), 28);
expect(huge.height(), 56);
// Shrink again. Reuse the last allocated surface.
final CkSurface shrunk2 = surface.acquireRenderSurface(ui.Size(5, 15));
expect(shrunk2, same(huge));
});
}, skip: isIosSafari);
}