This repository has been archived by the owner on Feb 25, 2025. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fix compute physicalX/Y for TalkBack events.
Extracted compute function to a helper file.
- Loading branch information
Showing
5 changed files
with
124 additions
and
24 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
113 changes: 113 additions & 0 deletions
113
lib/web_ui/lib/src/engine/pointer_binding/event_position_helper.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
// 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. | ||
|
||
import 'package:ui/ui.dart' as ui show Offset; | ||
|
||
import '../dom.dart'; | ||
import '../semantics.dart' show EngineSemanticsOwner; | ||
|
||
/// Returns an [ui.Offset] of the position of [event], relative to the position of [actualTarget]. | ||
/// | ||
/// The offset is *not* multiplied by DPR or anything else, it's the closest | ||
/// to what the DOM would return if we had currentTarget readily available. | ||
/// | ||
/// This needs an `actualTarget`, because the `event.currentTarget` (which is what | ||
/// this would really need to use) gets lost when the `event` comes from a "coalesced" | ||
/// event. | ||
/// | ||
/// It also takes into account semantics being enabled to fix the case where | ||
/// offsetX, offsetY == 0 (TalkBack events). | ||
// | ||
// TODO(dit): Make this understand 3D transforms in the platform view case, https://github.com/flutter/flutter/issues/117091 | ||
ui.Offset computeEventOffsetToTarget(DomMouseEvent event, DomElement actualTarget) { | ||
// On top of a platform view | ||
if (event.target != actualTarget) { | ||
return _computeOffsetOnPlatformView(event, actualTarget); | ||
} | ||
// On a TalkBack event | ||
if (EngineSemanticsOwner.instance.semanticsEnabled && event.offsetX == 0 && event.offsetY == 0) { | ||
return _computeOffsetForTalkbackEvent(event, actualTarget); | ||
} | ||
// Return the offsetX/Y in the normal case. | ||
return ui.Offset(event.offsetX, event.offsetY); | ||
} | ||
|
||
/// Computes the event offset when hovering over a platformView. | ||
/// | ||
/// This still uses offsetX/Y, but adds the offset from the top/left corner of the | ||
/// platform view to the glass pane (`actualTarget`). | ||
/// | ||
/// ×--FlutterView(actualTarget)--------------+ | ||
/// |\ | | ||
/// | x1,y1 | | ||
/// | | | ||
/// | | | ||
/// | ×-PlatformView(target)---------+ | | ||
/// | |\ | | | ||
/// | | x2,y2 | | | ||
/// | | | | | ||
/// | | × (event) | | | ||
/// | | \ | | | ||
/// | | offsetX, offsetY | | | ||
/// | | (Relative to PlatformView) | | | ||
/// | +------------------------------+ | | ||
/// +-----------------------------------------+ | ||
/// | ||
/// Offset between PlatformView and FlutterView (xP, yP) = (x2 - x1, y2 - y1) | ||
/// | ||
/// Event offset relative to FlutterView = (offsetX + xP, offsetY + yP) | ||
ui.Offset _computeOffsetOnPlatformView(DomMouseEvent event, DomElement actualTarget) { | ||
final DomElement target = event.target! as DomElement; | ||
final DomRect targetRect = target.getBoundingClientRect(); | ||
final DomRect actualTargetRect = actualTarget.getBoundingClientRect(); | ||
final double offsetTop = targetRect.y - actualTargetRect.y; | ||
final double offsetLeft = targetRect.x - actualTargetRect.x; | ||
return ui.Offset(event.offsetX + offsetLeft, event.offsetY + offsetTop); | ||
} | ||
|
||
/// Computes the event offset when TalkBack is firing the event. | ||
/// | ||
/// In this case, we need to use the clientX/Y position of the event (which are | ||
/// relative to the absolute top-left corner of the page, including scroll), then | ||
/// deduct the offsetLeft/Top from every offsetParent of the `actualTarget`. | ||
/// | ||
/// ×-Page----║-------------------------------+ | ||
/// | ║ | | ||
/// | ×-------║--------offsetParent(s)-----+ | | ||
/// | |\ | | | ||
/// | | offsetLeft, offsetTop | | | ||
/// | | | | | ||
/// | | | | | ||
/// | | ×-----║-------------actualTarget-+ | | | ||
/// | | | | | | | ||
/// ═════ × ─ (scrollLeft, scrollTop)═ ═ ═ | ||
/// | | | | | | | ||
/// | | | × | | | | ||
/// | | | \ | | | | ||
/// | | | clientX, clientY | | | | ||
/// | | | (Relative to Page + Scroll) | | | | ||
/// | | +-----║--------------------------+ | | | ||
/// | +-------║----------------------------+ | | ||
/// +---------║-------------------------------+ | ||
/// | ||
/// Computing the offset of the event relative to the actualTarget requires to | ||
/// compute the clientX, clientY of the actualTarget. To do that, we iterate | ||
/// up the offsetParent elements of actualTarget adding their offset and scroll | ||
/// positions. Finally, we deduct that from clientX, clientY of the event. | ||
ui.Offset _computeOffsetForTalkbackEvent(DomMouseEvent event, DomElement actualTarget) { | ||
assert(EngineSemanticsOwner.instance.semanticsEnabled); | ||
// Use clientX/clientY as the position of the event (this is relative to | ||
// the top left of the page, including scroll) | ||
double offsetX = event.clientX; | ||
double offsetY = event.clientY; | ||
// Compute the scroll offset of actualTarget | ||
DomHTMLElement parent = actualTarget as DomHTMLElement; | ||
while(parent.offsetParent != null){ | ||
offsetX -= parent.offsetLeft - parent.scrollLeft; | ||
offsetY -= parent.offsetTop - parent.scrollTop; | ||
parent = parent.offsetParent!; | ||
} | ||
return ui.Offset(offsetX, offsetY); | ||
} |