blob: ea0f0d17cac7546ca7db533e9c5487dcaa936587 [file] [log] [blame]
// Copyright 2018 The Chromium 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 "ios/web/navigation/wk_navigation_action_util.h"
#import <WebKit/WebKit.h>
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
namespace web {
NavigationActionInitiationType GetNavigationActionInitiationType(
WKNavigationAction* action) {
if (UIAccessibilityIsVoiceOverRunning())
return GetNavigationActionInitiationTypeWithVoiceOverOn(action.description);
return GetNavigationActionInitiationTypeWithVoiceOverOff(action.description);
}
// Returns the NavigationAction initiation type based on the string description
// of WKNavigationAction object when voice over is off.
// WKNavigationAction lacks public APIs to access KNavigationAction properties,
// and for that this function parses the description string of the object to get
// information about the action initiator. It uses the SyntheticClickType to
// indentify if there was a user guesture.
// Example description where the syntheticClickType is set:
// "<classname: 0x123124; navigationType = 2; syntheticClickType = 1;
// position x = 90.20 y = 10.29 request = null; ..>"
// SyntheticClickType still can be 0 for user-initiated actions.
NavigationActionInitiationType
GetNavigationActionInitiationTypeWithVoiceOverOff(
NSString* action_description) {
NSRegularExpression* click_type_regex = [NSRegularExpression
regularExpressionWithPattern:@"\\bsyntheticClickType = ([0-2]);"
options:NSRegularExpressionCaseInsensitive
error:nil];
NSTextCheckingResult* click_type_match_result = [click_type_regex
firstMatchInString:action_description
options:0
range:NSMakeRange(0, action_description.length)];
if (![click_type_match_result rangeAtIndex:0].length)
return NavigationActionInitiationType::kUnknownInitiator;
NSRange match_range = [click_type_match_result rangeAtIndex:1];
// SyntheticClickType represents the user action that happened to initiate
// this navigation values can be {0: NoTap, 1: OneFingerTap, 2:
// TwoFingerTap}.
int click_type = [action_description substringWithRange:match_range].intValue;
return click_type ? NavigationActionInitiationType::kUserInitiated
: NavigationActionInitiationType::kUnknownInitiator;
}
// Returns the NavigationAction initiation type based on the string description
// of WKNavigationAction object when voice over is on.
// In the voice over case, SyntheticClickType field is not filled so so this
// function uses the coordinates of the touch on the root view to indentify if
// there was a user guesture.
// Example description where only position is set:
// "<classname: 0x121124; navigationType = 1; syntheticClickType = 0;
// position x = 90.20 y = 10.29 request = null; ..>"
// Both coordinates still can be 0 for user-initiated actions.
NavigationActionInitiationType GetNavigationActionInitiationTypeWithVoiceOverOn(
NSString* action_description) {
NSRegularExpression* position_regex = [NSRegularExpression
regularExpressionWithPattern:@"\\bposition x = ([0-9]+\\.?[0-9]+) y = "
@"([0-9]+\\.?[0-9]+)\\b"
options:NSRegularExpressionCaseInsensitive
error:nil];
NSTextCheckingResult* position_match_result = [position_regex
firstMatchInString:action_description
options:0
range:NSMakeRange(0, action_description.length)];
if (![position_match_result rangeAtIndex:0].length)
return NavigationActionInitiationType::kUnknownInitiator;
float position_x =
[action_description
substringWithRange:[position_match_result rangeAtIndex:1]]
.floatValue;
float position_y =
[action_description
substringWithRange:[position_match_result rangeAtIndex:2]]
.floatValue;
return (position_y || position_x)
? NavigationActionInitiationType::kUserInitiated
: NavigationActionInitiationType::kUnknownInitiator;
}
} // namespace web