Skip to content

Commit

Permalink
Added workaround for ios safari iframe issue (flutter#32415)
Browse files Browse the repository at this point in the history
  • Loading branch information
nbayati authored May 17, 2022
1 parent ac3e6d4 commit e312797
Show file tree
Hide file tree
Showing 31 changed files with 73 additions and 74 deletions.
11 changes: 11 additions & 0 deletions lib/web_ui/lib/src/engine/browser_detection.dart
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,17 @@ bool get isIOS15 {
domWindow.navigator.userAgent.contains('OS 15_');
}

/// Returns true if the browser is iOS Safari, false otherwise.
bool get isIosSafari =>
browserEngine == BrowserEngine.webkit &&
operatingSystem == OperatingSystem.iOs;

/// Whether the current browser is Safari.
bool get isSafari => browserEngine == BrowserEngine.webkit;

/// Whether the current browser is Firefox.
bool get isFirefox => browserEngine == BrowserEngine.firefox;

/// Use in tests to simulate the detection of iOS 15.
bool? debugIsIOS15;

Expand Down
35 changes: 26 additions & 9 deletions lib/web_ui/lib/src/engine/pointer_binding.dart
Original file line number Diff line number Diff line change
Expand Up @@ -62,27 +62,44 @@ int convertButtonToButtons(int button) {
}
}

/// Wrapping the Safari iOS workaround that adds a dummy event listener
/// More info about the issue and workaround: https://github.com/flutter/flutter/issues/70858
class SafariPointerEventWorkaround {
static SafariPointerEventWorkaround instance = SafariPointerEventWorkaround();

void workAroundMissingPointerEvents() {
html.document.addEventListener('touchstart', (html.Event event) {});
}
}

class PointerBinding {
/// The singleton instance of this object.
static PointerBinding? get instance => _instance;
static PointerBinding? _instance;

static void initInstance(html.Element glassPaneElement) {
if (_instance == null) {
_instance = PointerBinding._(glassPaneElement);
_instance = PointerBinding(glassPaneElement);
assert(() {
registerHotRestartListener(() {
_instance!._adapter.clearListeners();
_instance!._pointerDataConverter.clearPointerState();
});
registerHotRestartListener(_instance!.dispose);
return true;
}());
}
}

PointerBinding._(this.glassPaneElement)
/// Performs necessary clean up for PointerBinding including removing event listeners
/// and clearing the existing pointer state
void dispose() {
_adapter.clearListeners();
_pointerDataConverter.clearPointerState();
}

PointerBinding(this.glassPaneElement)
: _pointerDataConverter = PointerDataConverter(),
_detector = const PointerSupportDetector() {
if (isIosSafari) {
SafariPointerEventWorkaround.instance.workAroundMissingPointerEvents();
}
_adapter = _createAdapter();
}

Expand Down Expand Up @@ -158,10 +175,10 @@ abstract class _BaseAdapter {
}

/// Listeners that are registered through dart to js api.
static final Map<String, html.EventListener> _listeners =
final Map<String, html.EventListener> _listeners =
<String, html.EventListener>{};
/// Listeners that are registered through native javascript api.
static final Map<String, html.EventListener> _nativeListeners =
final Map<String, html.EventListener> _nativeListeners =
<String, html.EventListener>{};
final html.Element glassPaneElement;
_PointerDataCallback _callback;
Expand Down Expand Up @@ -290,7 +307,7 @@ mixin _WheelEventListenerMixin on _BaseAdapter {
'passive': false,
});
final html.EventListener jsHandler = allowInterop((html.Event event) => handler(event));
_BaseAdapter._nativeListeners['wheel'] = jsHandler;
_nativeListeners['wheel'] = jsHandler;
addJsEventListener(glassPaneElement, 'wheel', jsHandler, eventOptions);
}

Expand Down
2 changes: 0 additions & 2 deletions lib/web_ui/test/canvaskit/common.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@ import 'package:ui/src/engine.dart';
import 'package:ui/ui.dart' as ui;
import 'package:web_engine_tester/golden_tester.dart';

export '../common.dart';

/// Used in tests instead of [ProductionCollector] to control Skia object
/// collection explicitly, and to prevent leaks across tests.
///
Expand Down
1 change: 1 addition & 0 deletions lib/web_ui/test/canvaskit/frame_timings_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import 'package:test/bootstrap/browser.dart';
import 'package:test/test.dart';
import 'package:ui/src/engine/browser_detection.dart';

import '../frame_timings_common.dart';
import 'common.dart';
Expand Down
2 changes: 0 additions & 2 deletions lib/web_ui/test/canvaskit/hot_restart_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ import 'package:test/bootstrap/browser.dart';
import 'package:test/test.dart';
import 'package:ui/src/engine.dart';

import 'common.dart';

void main() {
internalBootstrapBrowserTest(() => testMain);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ import 'package:test/bootstrap/browser.dart';
import 'package:test/test.dart';
import 'package:ui/src/engine.dart';

import 'common.dart';

void main() {
internalBootstrapBrowserTest(() => testMain);
}
Expand Down
2 changes: 0 additions & 2 deletions lib/web_ui/test/canvaskit/scene_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@ 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);
}
Expand Down
1 change: 1 addition & 0 deletions lib/web_ui/test/canvaskit/semantics_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import 'dart:async';

import 'package:test/bootstrap/browser.dart';
import 'package:test/test.dart';
import 'package:ui/src/engine/browser_detection.dart';

import '../engine/semantics/semantics_test.dart';
import 'common.dart';
Expand Down
2 changes: 0 additions & 2 deletions lib/web_ui/test/canvaskit/skia_font_collection_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@ import 'package:test/test.dart';

import 'package:ui/src/engine.dart';

import 'common.dart';

void main() {
internalBootstrapBrowserTest(() => testMain);
}
Expand Down
1 change: 1 addition & 0 deletions lib/web_ui/test/canvaskit/text_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import 'package:test/bootstrap/browser.dart';
import 'package:test/test.dart';
import 'package:ui/src/engine/browser_detection.dart';
import 'package:ui/ui.dart' as ui;

import 'common.dart';
Expand Down
15 changes: 0 additions & 15 deletions lib/web_ui/test/common.dart

This file was deleted.

43 changes: 32 additions & 11 deletions lib/web_ui/test/engine/pointer_binding_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,6 @@ void _testEach<T extends _BasicEventContext>(

/// Some methods in this class are skipped for iOS-Safari.
// TODO(mdebbar): https://github.com/flutter/flutter/issues/60033
bool get isIosSafari => browserEngine == BrowserEngine.webkit &&
operatingSystem == OperatingSystem.iOs;

void main() {
internalBootstrapBrowserTest(() => testMain);
Expand All @@ -55,6 +53,15 @@ void testMain() {
dpi = window.devicePixelRatio;
});

test('ios workaround', () {
final MockSafariPointerEventWorkaround mockSafariPointer =
MockSafariPointerEventWorkaround();
SafariPointerEventWorkaround.instance = mockSafariPointer;
final PointerBinding instance = PointerBinding(html.DivElement());
expect(mockSafariPointer.workAroundInvoked, isIosSafari);
instance.dispose();
}, skip: !isIosSafari);

test('_PointerEventContext generates expected events', () {
if (!_PointerEventContext().isSupported) {
return;
Expand Down Expand Up @@ -1226,7 +1233,7 @@ void testMain() {
_PointerEventContext(),
],
'correctly handles missing right mouse button up when followed by move',
(_ButtonedEventMixin context) {
(_ButtonedEventMixin context) {
PointerBinding.instance!.debugOverrideDetector(context);
// This can happen with the following gesture sequence:
//
Expand Down Expand Up @@ -1787,8 +1794,7 @@ void testMain() {
expect(packets, hasLength(1));
expect(packets[0].data, hasLength(1));
expect(packets[0].data[0].change, equals(ui.PointerChange.move));
expect(packets[0].data[0].physicalX,
equals(900.0 * dpi));
expect(packets[0].data[0].physicalX, equals(900.0 * dpi));
expect(packets[0].data[0].physicalY, equals(1900.0 * dpi));
packets.clear();

Expand Down Expand Up @@ -2241,6 +2247,15 @@ void testMain() {
);
}

class MockSafariPointerEventWorkaround implements SafariPointerEventWorkaround {
bool workAroundInvoked = false;

@override
void workAroundMissingPointerEvents() {
workAroundInvoked = true;
}
}

abstract class _BasicEventContext implements PointerSupportDetector {
String get name;

Expand Down Expand Up @@ -2275,10 +2290,14 @@ mixin _ButtonedEventMixin on _BasicEventContext {
//
// If there is no button change, assign `button` with _kNoButtonChange.
html.Event mouseMove(
{double? clientX, double? clientY, required int button, required int buttons});
{double? clientX,
double? clientY,
required int button,
required int buttons});

// Generate an event that releases all mouse buttons.
html.Event mouseUp({double? clientX, double? clientY, int? button, int? buttons});
html.Event mouseUp(
{double? clientX, double? clientY, int? button, int? buttons});

html.Event hover({double? clientX, double? clientY}) {
return mouseMove(
Expand Down Expand Up @@ -2325,7 +2344,8 @@ mixin _ButtonedEventMixin on _BasicEventContext {
required double? deltaX,
required double? deltaY,
}) {
final Function jsWheelEvent = js_util.getProperty<Function>(html.window, 'WheelEvent');
final Function jsWheelEvent =
js_util.getProperty<Function>(html.window, 'WheelEvent');
final List<dynamic> eventArgs = <dynamic>[
'wheel',
<String, dynamic>{
Expand Down Expand Up @@ -2396,8 +2416,7 @@ mixin _MultiPointerEventMixin on _BasicEventContext {
class _TouchEventContext extends _BasicEventContext
with _MultiPointerEventMixin
implements PointerSupportDetector {
_TouchEventContext() :
_target = html.document.createElement('div');
_TouchEventContext() : _target = html.document.createElement('div');

@override
String get name => 'TouchAdapter';
Expand Down Expand Up @@ -2518,7 +2537,9 @@ class _MouseEventContext extends _BasicEventContext
hasButtonChange && (buttons & convertButtonToButtons(button)) != 0;
final String adjustedType = !hasButtonChange
? 'mousemove'
: changeIsButtonDown ? 'mousedown' : 'mouseup';
: changeIsButtonDown
? 'mousedown'
: 'mouseup';
final int adjustedButton = hasButtonChange ? button : 0;
return _createMouseEvent(
adjustedType,
Expand Down
1 change: 0 additions & 1 deletion lib/web_ui/test/engine/semantics/semantics_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import 'package:test/test.dart';
import 'package:ui/src/engine.dart';
import 'package:ui/ui.dart' as ui;

import '../../common.dart';
import 'semantics_tester.dart';

DateTime _testTime = DateTime(2018, 12, 17);
Expand Down
1 change: 0 additions & 1 deletion lib/web_ui/test/html/bitmap_canvas_golden_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import 'package:ui/src/engine.dart';
import 'package:ui/ui.dart';

import 'package:web_engine_tester/golden_tester.dart';
import '../common.dart';
import 'screenshot.dart';

void main() {
Expand Down
3 changes: 1 addition & 2 deletions lib/web_ui/test/html/canvas_context_golden_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,11 @@ import 'dart:html' as html;
import 'package:test/bootstrap/browser.dart';
import 'package:test/test.dart';
import 'package:ui/src/engine.dart' as engine;
import 'package:ui/src/engine/browser_detection.dart';
import 'package:ui/ui.dart' hide TextStyle;

import 'package:web_engine_tester/golden_tester.dart';

import '../common.dart';

void main() {
internalBootstrapBrowserTest(() => testMain);
}
Expand Down
2 changes: 0 additions & 2 deletions lib/web_ui/test/html/canvas_reuse_golden_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@ import 'package:ui/ui.dart' hide TextStyle;

import 'package:web_engine_tester/golden_tester.dart';

import '../common.dart';

void main() {
internalBootstrapBrowserTest(() => testMain);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import 'package:ui/ui.dart';

import 'package:web_engine_tester/golden_tester.dart';

import '../../common.dart';
import '../screenshot.dart';

void main() {
Expand Down
2 changes: 0 additions & 2 deletions lib/web_ui/test/html/drawing/canvas_rrect_golden_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@ import 'package:ui/ui.dart';

import 'package:web_engine_tester/golden_tester.dart';

import '../../common.dart';

void main() {
internalBootstrapBrowserTest(() => testMain);
}
Expand Down
2 changes: 0 additions & 2 deletions lib/web_ui/test/html/drawing/draw_vertices_golden_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@ import 'package:ui/ui.dart' hide TextStyle, ImageShader;

import 'package:web_engine_tester/golden_tester.dart';

import '../../common.dart';

void main() {
internalBootstrapBrowserTest(() => testMain);
}
Expand Down
2 changes: 0 additions & 2 deletions lib/web_ui/test/html/paragraph/helper.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@ import 'package:ui/src/engine.dart';
import 'package:ui/ui.dart';
import 'package:web_engine_tester/golden_tester.dart';

import '../../common.dart';

const Color white = Color(0xFFFFFFFF);
const Color black = Color(0xFF000000);
const Color red = Color(0xFFFF0000);
Expand Down
2 changes: 0 additions & 2 deletions lib/web_ui/test/html/paragraph/text_scuba.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@ import 'package:ui/ui.dart' as ui;

import 'package:web_engine_tester/golden_tester.dart';

import '../../common.dart';

/// Class that controls some details of how screenshotting is made.
///
/// (For Googlers: Not really related with internal Scuba anymore)
Expand Down
1 change: 0 additions & 1 deletion lib/web_ui/test/html/path_metrics_golden_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import 'package:ui/src/engine.dart';
import 'package:ui/ui.dart' hide TextStyle;
import 'package:web_engine_tester/golden_tester.dart';

import '../common.dart';
import '../matchers.dart';

void main() {
Expand Down
2 changes: 0 additions & 2 deletions lib/web_ui/test/html/path_to_svg_golden_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@ import 'package:ui/ui.dart';

import 'package:web_engine_tester/golden_tester.dart';

import '../common.dart';

void main() {
internalBootstrapBrowserTest(() => testMain);
}
Expand Down
2 changes: 0 additions & 2 deletions lib/web_ui/test/html/path_transform_golden_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@ import 'package:ui/ui.dart' hide TextStyle;

import 'package:web_engine_tester/golden_tester.dart';

import '../common.dart';

void main() {
internalBootstrapBrowserTest(() => testMain);
}
Expand Down
Loading

0 comments on commit e312797

Please sign in to comment.