@@ -59,6 +59,11 @@ class Surface {
5959 /// due to the browser tab becoming dormant.
6060 final html.Element htmlElement = html.Element .tag ('flt-canvas-container' );
6161
62+ /// The underlying `<canvas>` element used for this surface.
63+ html.CanvasElement ? htmlCanvas;
64+ int _pixelWidth = - 1 ;
65+ int _pixelHeight = - 1 ;
66+
6267 /// Specify the GPU resource cache limits.
6368 void setSkiaResourceCacheMaxBytes (int bytes) {
6469 _skiaCacheBytes = bytes;
@@ -102,6 +107,7 @@ class Surface {
102107 }
103108
104109 ui.Size ? _currentSize;
110+ double _currentDevicePixelRatio = - 1 ;
105111
106112 CkSurface _createOrUpdateSurfaces (ui.Size size) {
107113 if (size.isEmpty) {
@@ -116,9 +122,13 @@ class Surface {
116122 size.width <= previousSize.width &&
117123 size.height <= previousSize.height) {
118124 // The existing surface is still reusable.
125+ if (window.devicePixelRatio != _currentDevicePixelRatio) {
126+ _updateLogicalHtmlCanvasSize ();
127+ }
119128 return _surface! ;
120129 }
121130
131+ _currentDevicePixelRatio = window.devicePixelRatio;
122132 _currentSize = _currentSize == null
123133 // First frame. Allocate a canvas of the exact size as the window. The
124134 // window is frequently never resized, particularly on mobile, so using
@@ -131,36 +141,44 @@ class Surface {
131141 _surface = null ;
132142 _addedToScene = false ;
133143
134- return _surface = _wrapHtmlCanvas (_currentSize! );
144+ return _surface = _createNewSurface (_currentSize! );
135145 }
136146
137- CkSurface _wrapHtmlCanvas (ui.Size physicalSize) {
138- // Clear the container, if it's not empty.
139- while (htmlElement.firstChild != null ) {
140- htmlElement.firstChild! .remove ();
141- }
147+ /// Sets the CSS size of the canvas so that canvas pixels are 1:1 with device
148+ /// pixels.
149+ ///
150+ /// The logical size of the canvas is not based on the size of the window
151+ /// but on the size of the canvas, which, due to `ceil()` above, may not be
152+ /// the same as the window. We do not round/floor/ceil the logical size as
153+ /// CSS pixels can contain more than one physical pixel and therefore to
154+ /// match the size of the window precisely we use the most precise floating
155+ /// point value we can get.
156+ void _updateLogicalHtmlCanvasSize () {
157+ final double logicalWidth = _pixelWidth / ui.window.devicePixelRatio;
158+ final double logicalHeight = _pixelHeight / ui.window.devicePixelRatio;
159+ htmlCanvas! .style
160+ ..width = '${logicalWidth }px'
161+ ..height = '${logicalHeight }px' ;
162+ }
163+
164+ /// This function is expensive.
165+ ///
166+ /// It's better to reuse surface if possible.
167+ CkSurface _createNewSurface (ui.Size physicalSize) {
168+ // Clear the container, if it's not empty. We're going to create a new <canvas>.
169+ this .htmlCanvas? .remove ();
142170
143171 // If `physicalSize` is not precise, use a slightly bigger canvas. This way
144172 // we ensure that the rendred picture covers the entire browser window.
145- final int pixelWidth = physicalSize.width.ceil ();
146- final int pixelHeight = physicalSize.height.ceil ();
173+ _pixelWidth = physicalSize.width.ceil ();
174+ _pixelHeight = physicalSize.height.ceil ();
147175 final html.CanvasElement htmlCanvas = html.CanvasElement (
148- width: pixelWidth ,
149- height: pixelHeight ,
176+ width: _pixelWidth ,
177+ height: _pixelHeight ,
150178 );
151-
152- // The logical size of the canvas is not based on the size of the window
153- // but on the size of the canvas, which, due to `ceil()` above, may not be
154- // the same as the window. We do not round/floor/ceil the logical size as
155- // CSS pixels can contain more than one physical pixel and therefore to
156- // match the size of the window precisely we use the most precise floating
157- // point value we can get.
158- final double logicalWidth = pixelWidth / ui.window.devicePixelRatio;
159- final double logicalHeight = pixelHeight / ui.window.devicePixelRatio;
160- htmlCanvas.style
161- ..position = 'absolute'
162- ..width = '${logicalWidth }px'
163- ..height = '${logicalHeight }px' ;
179+ this .htmlCanvas = htmlCanvas;
180+ htmlCanvas.style.position = 'absolute' ;
181+ _updateLogicalHtmlCanvasSize ();
164182
165183 // When the browser tab using WebGL goes dormant the browser and/or OS may
166184 // decide to clear GPU resources to let other tabs/programs use the GPU.
@@ -212,8 +230,8 @@ class Surface {
212230
213231 SkSurface ? skSurface = canvasKit.MakeOnScreenGLSurface (
214232 _grContext! ,
215- pixelWidth ,
216- pixelHeight ,
233+ _pixelWidth ,
234+ _pixelHeight ,
217235 SkColorSpaceSRGB ,
218236 );
219237
0 commit comments