Skip to content

Commit

Permalink
Cherry-pick 265870.476@safari-7616-branch (5cfdf9b). https://bugs.web…
Browse files Browse the repository at this point in the history
…kit.org/show_bug.cgi?id=260864

    [iOS] Keyboard should not learn autocorrections after revealing password in Gmail login flow
    https://bugs.webkit.org/show_bug.cgi?id=260864
    rdar://111393742

    Reviewed by Aditya Keerthi.

    When focusing and editing secure inputs (i.e. input type="password"), we set `isSecureTextEntry` on
    `UITextInputTraits` to `YES`, which disables autocorrection learning when the user types in this
    field, suppresses the keyboard in screen recordings, and more.

    However, some webpages (e.g. Gmail login) offer the ability to reveal the password as plain text as
    a convenience to the user — this typically works by changing the input type from `"password"` to
    just `"text"`. This currently causes all of the secure text entry behaviors to be disabled, which
    includes disabling correction learning; this is undesirable, since the password may be offered as an
    autocorrection candidate when editing in other plain text fields in the future, in non-secure
    contexts.

    Because the user opted to reveal the input, it doesn't really make sense to treat the input as fully
    secure (for instance, there's no reason to suppress keyboard visibility in screen recordings if the
    password text itself is fully visible). However, we need to (at least) prevent the keyboard from
    learning suggestions when typing in this field. To achieve this, we add a flag on `HTMLInputElement`
    to remember whether it was ever a password field; if so, we set the `-learnsCorrections` property on
    text input traits to `NO`.

    Test: AutocorrectionTests.DoNotLearnCorrectionsAfterChangingInputTypeFromPassword

    * Source/WebCore/html/HTMLInputElement.cpp:
    (WebCore::HTMLInputElement::runPostTypeUpdateTasks):

    Set `m_hasEverBeenPasswordField` here.

    * Source/WebCore/html/HTMLInputElement.h:
    (WebCore::HTMLInputElement::hasEverBeenPasswordField const):
    * Source/WebKit/Platform/spi/ios/UIKitSPI.h:
    * Source/WebKit/Shared/FocusedElementInformation.h:
    * Source/WebKit/Shared/FocusedElementInformation.serialization.in:
    * Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm:
    (-[WKContentView _updateTextInputTraits:]):

    Consult `hasEverBeenPasswordField` on the focused element information, and disable learning from
    corrections if it's set.

    * Source/WebKit/WebProcess/WebPage/ios/WebPageIOS.mm:

    Propagate `hasEverBeenPasswordField` state to the UI process when focusing an input element.

    (WebKit::WebPage::focusedElementInformation):
    * Tools/TestWebKitAPI/Tests/ios/AutocorrectionTestsIOS.mm:

    Add an API test to exercise the change.

    * Tools/TestWebKitAPI/ios/UIKitSPI.h:

    Canonical link: https://commits.webkit.org/265870.476@safari-7616-branch
  • Loading branch information
whsieh authored and aperezdc committed Oct 19, 2023
1 parent f843025 commit 331906e
Show file tree
Hide file tree
Showing 9 changed files with 42 additions and 2 deletions.
3 changes: 3 additions & 0 deletions Source/WebCore/html/HTMLInputElement.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -610,6 +610,9 @@ inline void HTMLInputElement::runPostTypeUpdateTasks()
}
#endif

if (isPasswordField())
m_hasEverBeenPasswordField = true;

if (renderer())
invalidateStyleAndRenderersForSubtree();

Expand Down
3 changes: 3 additions & 0 deletions Source/WebCore/html/HTMLInputElement.h
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,8 @@ class HTMLInputElement : public HTMLTextFormControlElement {
bool isInnerTextElementEditable() const final { return !hasAutoFillStrongPasswordButton() && HTMLTextFormControlElement::isInnerTextElementEditable(); }
void finishParsingChildren() final;

bool hasEverBeenPasswordField() const { return m_hasEverBeenPasswordField; }

protected:
HTMLInputElement(const QualifiedName&, Document&, HTMLFormElement*, bool createdByParser);

Expand Down Expand Up @@ -476,6 +478,7 @@ class HTMLInputElement : public HTMLTextFormControlElement {
#endif
bool m_isSpellcheckDisabledExceptTextReplacement : 1 { false };
bool m_hasPendingUserAgentShadowTreeUpdate : 1 { false };
bool m_hasEverBeenPasswordField : 1 { false };
RefPtr<InputType> m_inputType;
// The ImageLoader must be owned by this element because the loader code assumes
// that it lives as long as its owning element lives. If we move the loader into
Expand Down
3 changes: 2 additions & 1 deletion Source/WebKit/Platform/spi/ios/UIKitSPI.h
Original file line number Diff line number Diff line change
Expand Up @@ -593,7 +593,8 @@ typedef enum {
@property (nonatomic, retain) UIColor *insertionPointColor;
@property (nonatomic, retain) UIColor *selectionBarColor;
@property (nonatomic, retain) UIColor *selectionHighlightColor;
@property (nonatomic, readwrite) BOOL isSingleLineDocument;
@property (nonatomic) BOOL isSingleLineDocument;
@property (nonatomic) BOOL learnsCorrections;
@end

@protocol UITextInputDelegatePrivate
Expand Down
1 change: 1 addition & 0 deletions Source/WebKit/Shared/FocusedElementInformation.h
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ struct FocusedElementInformation {
Vector<WebCore::Color> suggestedColors;
#endif
#endif
bool hasEverBeenPasswordField { false };
bool shouldSynthesizeKeyEventsForEditing { false };
bool isSpellCheckingEnabled { true };
bool shouldAvoidResizingWhenInputViewBoundsChange { false };
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ headers: "FocusedElementInformation.h" "WebCoreArgumentCoders.h"
Vector<WebCore::Color> suggestedColors;
#endif
#endif
bool hasEverBeenPasswordField;
bool shouldSynthesizeKeyEventsForEditing;
bool isSpellCheckingEnabled;
bool shouldAvoidResizingWhenInputViewBoundsChange;
Expand Down
3 changes: 3 additions & 0 deletions Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm
Original file line number Diff line number Diff line change
Expand Up @@ -6325,6 +6325,9 @@ - (void)_updateTextInputTraits:(id<UITextInputTraits>)traits
}
}

if ([privateTraits respondsToSelector:@selector(setLearnsCorrections:)] && _focusedElementInformation.hasEverBeenPasswordField)
privateTraits.learnsCorrections = NO;

if ([privateTraits respondsToSelector:@selector(setShortcutConversionType:)])
privateTraits.shortcutConversionType = _focusedElementInformation.elementType == WebKit::InputType::Password ? UITextShortcutConversionTypeNo : UITextShortcutConversionTypeDefault;

Expand Down
1 change: 1 addition & 0 deletions Source/WebKit/WebProcess/WebPage/ios/WebPageIOS.mm
Original file line number Diff line number Diff line change
Expand Up @@ -3671,6 +3671,7 @@ static void handleAnimationActions(Element& element, uint32_t action)
information.autocapitalizeType = element.autocapitalizeType();
information.isAutocorrect = element.shouldAutocorrect();
information.placeholder = element.attributeWithoutSynchronization(HTMLNames::placeholderAttr);
information.hasEverBeenPasswordField = element.hasEverBeenPasswordField();
if (element.isPasswordField())
information.elementType = InputType::Password;
else if (element.isSearchField())
Expand Down
26 changes: 26 additions & 0 deletions Tools/TestWebKitAPI/Tests/ios/AutocorrectionTestsIOS.mm
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,32 @@ static void checkCGRectIsEqualToCGRectWithLogging(CGRect expected, CGRect observ
EXPECT_EQ(0U, [contextAfterTyping contextAfterSelection].length);
}

TEST(AutocorrectionTests, DoNotLearnCorrectionsAfterChangingInputTypeFromPassword)
{
auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 568)]);
auto inputDelegate = adoptNS([TestInputDelegate new]);

bool startedInputSession = false;
[inputDelegate setFocusStartsInputSessionPolicyHandler:[&] (WKWebView *, id<_WKFocusedElementInfo>) -> _WKFocusStartsInputSessionPolicy {
startedInputSession = true;
return _WKFocusStartsInputSessionPolicyAllow;
}];
[webView _setInputDelegate:inputDelegate.get()];
[webView synchronouslyLoadHTMLString:@"<input id='first' type='password'></input><input id='second'></input>"];
[webView stringByEvaluatingJavaScript:@"let first = document.querySelector('#first'); first.type = 'text'; first.focus();"];
TestWebKitAPI::Util::run(&startedInputSession);

auto learnsCorrections = [&] {
return static_cast<id<UITextInputTraits_Private>>([webView textInputContentView].textInputTraits).learnsCorrections;
};
EXPECT_FALSE(learnsCorrections());

startedInputSession = false;
[webView stringByEvaluatingJavaScript:@"document.querySelector('#second').focus()"];
TestWebKitAPI::Util::run(&startedInputSession);
EXPECT_TRUE(learnsCorrections());
}

#if HAVE(AUTOCORRECTION_ENHANCEMENTS)

TEST(AutocorrectionTests, AutocorrectionIndicatorsDismissAfterNextWord)
Expand Down
3 changes: 2 additions & 1 deletion Tools/TestWebKitAPI/ios/UIKitSPI.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,8 @@ WTF_EXTERN_C_END
@protocol UITextInputTraits_Private <NSObject, UITextInputTraits>
@property (nonatomic, readonly) UIColor *insertionPointColor;
@property (nonatomic, readonly) UIColor *selectionBarColor;
@property (nonatomic, readwrite) BOOL isSingleLineDocument;
@property (nonatomic) BOOL isSingleLineDocument;
@property (nonatomic) BOOL learnsCorrections;
@end

@interface UITextInputTraits : NSObject <UITextInputTraits, UITextInputTraits_Private, NSCopying>
Expand Down

0 comments on commit 331906e

Please sign in to comment.