Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
WIP fixing semantics tests
  • Loading branch information
harryterkelsen committed Jan 11, 2024
commit d3757e76a0257739c0535d25010eaa2d010dce47
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ class MultiSurfaceViewRasterizer extends ViewRasterizer {
@override
final OverlayCanvasFactory<Surface> overlayFactory =
OverlayCanvasFactory<Surface>(
createCanvas: () => Surface(useOffscreenCanvas: false));
createCanvas: () => Surface(isRenderCanvas: true));

@override
void dispose() {
Expand All @@ -45,14 +45,14 @@ class MultiSurfaceViewRasterizer extends ViewRasterizer {

@override
void prepareToDraw() {
overlayFactory.baseCanvas.ensureSurface(currentFrameSize);
overlayFactory.baseCanvas.createOrUpdateSurface(currentFrameSize);
}

@override
Future<void> rasterizeToCanvas(
OverlayCanvas canvas, List<CkPicture> pictures) {
final Surface surface = canvas as Surface;
surface.ensureSurface(currentFrameSize);
surface.createOrUpdateSurface(currentFrameSize);
final CkCanvas skCanvas = surface.getCanvas();
skCanvas.clear(const ui.Color(0x00000000));
pictures.forEach(skCanvas.drawPicture);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,6 @@ class OffscreenCanvasViewRasterizer extends ViewRasterizer {

@override
void prepareToDraw() {
rasterizer.offscreenSurface.ensureSurface(currentFrameSize);
rasterizer.offscreenSurface.createOrUpdateSurface(currentFrameSize);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ class OverlayCanvasFactory<T extends OverlayCanvas> {
/// The base canvas to paint on. This is the default canvas which will be
/// painted to. If there are no platform views, then this canvas will render
/// the entire scene.
late final T baseCanvas = createCanvas();
late final T baseCanvas = createCanvas()..initialize();

/// Canvases created by this factory which are currently in use.
final List<T> _liveCanvases = <T>[];
Expand Down Expand Up @@ -51,6 +51,7 @@ class OverlayCanvasFactory<T extends OverlayCanvas> {
return canvas;
} else {
final T canvas = createCanvas();
canvas.initialize();
_liveCanvases.add(canvas);
return canvas;
}
Expand Down
6 changes: 6 additions & 0 deletions lib/web_ui/lib/src/engine/canvaskit/rasterizer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,12 @@ abstract class ViewRasterizer {
abstract class OverlayCanvas {
DomElement get htmlElement;

/// Whether or not this overlay canvas is attached to the DOM.
bool get isConnected;

/// Initialize the overlay.
void initialize();

/// Disposes this overlay.
void dispose();
}
9 changes: 9 additions & 0 deletions lib/web_ui/lib/src/engine/canvaskit/render_canvas.dart
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,15 @@ class RenderCanvas extends OverlayCanvas {
_updateLogicalHtmlCanvasSize();
}

@override
bool get isConnected => canvasElement.isConnected!;

@override
void initialize() {
// No extra initialization needed.
}

@override
void dispose() {
htmlElement.remove();
}
Expand Down
55 changes: 52 additions & 3 deletions lib/web_ui/lib/src/engine/canvaskit/surface.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import 'package:ui/ui.dart' as ui;

import '../browser_detection.dart';
import '../configuration.dart';
import '../display.dart';
import '../dom.dart';
import '../platform_dispatcher.dart';
import '../util.dart';
Expand Down Expand Up @@ -49,15 +50,18 @@ class SurfaceFrame {
/// successive frames if they are the same size. Otherwise, a new [CkSurface] is
/// created.
class Surface extends OverlayCanvas {
Surface({bool useOffscreenCanvas = true})
Surface({this.isRenderCanvas = false})
: useOffscreenCanvas =
Surface.offscreenCanvasSupported && useOffscreenCanvas;
Surface.offscreenCanvasSupported && !isRenderCanvas;

CkSurface? _surface;

/// Whether or not to use an `OffscreenCanvas` to back this [Surface].
final bool useOffscreenCanvas;

/// If `true`, this [Surface] is used for rendering.
final bool isRenderCanvas;

/// If true, forces a new WebGL context to be created, even if the window
/// size is the same. This is used to restore the UI after the browser tab
/// goes dormant and loses the GL context.
Expand Down Expand Up @@ -99,10 +103,11 @@ class Surface extends OverlayCanvas {
/// Note, if this getter is called, then this Surface is being used as an
/// overlay and must be backed by an onscreen <canvas> element.
@override
DomElement get htmlElement => _canvasElement!;
final DomElement htmlElement = createDomElement('flt-canvas-container');

int _pixelWidth = -1;
int _pixelHeight = -1;
double _currentDevicePixelRatio = -1;
int _sampleCount = -1;
int _stencilBits = -1;

Expand Down Expand Up @@ -179,6 +184,26 @@ class Surface extends OverlayCanvas {
ui.Size? _currentCanvasPhysicalSize;
ui.Size? _currentSurfaceSize;

/// Sets the CSS size of the canvas so that canvas pixels are 1:1 with device
/// pixels.
///
/// The logical size of the canvas is not based on the size of the window
/// but on the size of the canvas, which, due to `ceil()` above, may not be
/// the same as the window. We do not round/floor/ceil the logical size as
/// CSS pixels can contain more than one physical pixel and therefore to
/// match the size of the window precisely we use the most precise floating
/// point value we can get.
void _updateLogicalHtmlCanvasSize() {
final double devicePixelRatio =
EngineFlutterDisplay.instance.devicePixelRatio;
final double logicalWidth = _pixelWidth / devicePixelRatio;
final double logicalHeight = _pixelHeight / devicePixelRatio;
final DomCSSStyleDeclaration style = _canvasElement!.style;
style.width = '${logicalWidth}px';
style.height = '${logicalHeight}px';
_currentDevicePixelRatio = devicePixelRatio;
}

/// This is only valid after the first frame or if [ensureSurface] has been
/// called
bool get usingSoftwareBackend =>
Expand Down Expand Up @@ -218,6 +243,11 @@ class Surface extends OverlayCanvas {
if (previousSurfaceSize != null &&
size.width == previousSurfaceSize.width &&
size.height == previousSurfaceSize.height) {
final double devicePixelRatio =
EngineFlutterDisplay.instance.devicePixelRatio;
if (isRenderCanvas && devicePixelRatio != _currentDevicePixelRatio) {
_updateLogicalHtmlCanvasSize();
}
return _surface!;
}

Expand All @@ -240,6 +270,9 @@ class Surface extends OverlayCanvas {
_currentCanvasPhysicalSize = newSize;
_pixelWidth = newSize.width.ceil();
_pixelHeight = newSize.height.ceil();
if (isRenderCanvas) {
_updateLogicalHtmlCanvasSize();
}
}
}

Expand Down Expand Up @@ -311,6 +344,7 @@ class Surface extends OverlayCanvas {
_cachedContextLostListener,
false,
);
_canvasElement!.remove();
_canvasElement = null;
_cachedContextRestoredListener = null;
_cachedContextLostListener = null;
Expand All @@ -335,6 +369,12 @@ class Surface extends OverlayCanvas {
htmlCanvas = canvas;
_canvasElement = canvas;
_offscreenCanvas = null;
if (isRenderCanvas) {
_canvasElement!.setAttribute('aria-hidden', 'true');
_canvasElement!.style.position = 'absolute';
htmlElement.append(_canvasElement!);
_updateLogicalHtmlCanvasSize();
}
}

// When the browser tab using WebGL goes dormant the browser and/or OS may
Expand Down Expand Up @@ -458,6 +498,15 @@ class Surface extends OverlayCanvas {
return true;
}

@override
bool get isConnected => _canvasElement!.isConnected!;

@override
void initialize() {
ensureSurface();
}

@override
void dispose() {
_offscreenCanvas?.removeEventListener(
'webglcontextlost', _cachedContextLostListener, false);
Expand Down
1 change: 1 addition & 0 deletions lib/web_ui/lib/src/engine/platform_dispatcher.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1237,6 +1237,7 @@ class EnginePlatformDispatcher extends ui.PlatformDispatcher {
/// Otherwise zones won't work properly.
void invokeOnSemanticsAction(
int nodeId, ui.SemanticsAction action, ByteData? args) {
print('invoking semantics action callback!');
invoke1<ui.SemanticsActionEvent>(
_onSemanticsActionEvent,
_onSemanticsActionEventZone,
Expand Down
17 changes: 11 additions & 6 deletions lib/web_ui/lib/src/engine/semantics/focusable.dart
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,8 @@ class Focusable extends RoleManager {
if (!_focusManager.isManaging) {
_focusManager.manage(semanticsObject.id, owner.element);
}
_focusManager.changeFocus(semanticsObject.hasFocus && (!semanticsObject.hasEnabledState || semanticsObject.isEnabled));
_focusManager.changeFocus(semanticsObject.hasFocus &&
(!semanticsObject.hasEnabledState || semanticsObject.isEnabled));
} else {
_focusManager.stopManaging();
}
Expand Down Expand Up @@ -175,6 +176,7 @@ class AccessibilityFocusManager {

void _setFocusFromDom(bool acquireFocus) {
final _FocusTarget? target = _target;
print('hit setFocus callback on ${target?.element}');

if (target == null) {
// DOM events can be asynchronous. By the time the event reaches here, the
Expand All @@ -185,15 +187,16 @@ class AccessibilityFocusManager {
EnginePlatformDispatcher.instance.invokeOnSemanticsAction(
target.semanticsNodeId,
acquireFocus
? ui.SemanticsAction.didGainAccessibilityFocus
: ui.SemanticsAction.didLoseAccessibilityFocus,
? ui.SemanticsAction.didGainAccessibilityFocus
: ui.SemanticsAction.didLoseAccessibilityFocus,
null,
);
}

/// Requests focus or blur on the DOM element.
void changeFocus(bool value) {
final _FocusTarget? target = _target;
print('calling changeFocus on $target!!!');

if (target == null) {
// If this branch is being executed, there's a bug somewhere already, but
Expand All @@ -203,9 +206,8 @@ class AccessibilityFocusManager {
// Nothing is being managed right now.
assert(() {
printWarning(
'Cannot change focus to $value. No element is being managed by this '
'AccessibilityFocusManager.'
);
'Cannot change focus to $value. No element is being managed by this '
'AccessibilityFocusManager.');
return true;
}());
return;
Expand Down Expand Up @@ -237,6 +239,8 @@ class AccessibilityFocusManager {
return;
}

print('ADDING POST UPDATE CALLBACK TO FOCUS THE ELEMENT!!!');

// Delay the focus request until the final DOM structure is established
// because the element may not yet be attached to the DOM, or it may be
// reparented and lose focus again.
Expand All @@ -249,6 +253,7 @@ class AccessibilityFocusManager {
return;
}

print('CALLING FOCUS ON ${target.element}!!!!!');
target.element.focus();
});
}
Expand Down
Loading