summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2018-01-29 11:01:19 +0100
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2018-02-02 09:41:31 +0000
commit5cb725e1b4b8e313c7d847ae46c1dbe3fbfaaa57 (patch)
tree682ae31aef0c4bf3fadffeb40a21def57971097e
parent0d62ec3da6b22576c666a839dddb7105f0047a68 (diff)
downloadqtwebengine-chromium-5cb725e1b4b8e313c7d847ae46c1dbe3fbfaaa57.tar.gz
[Backport] [Autofill] Use ShadowDOM placeholder to preview suggestions.
The first patch is a re-upload of https://chromium-review.googlesource.com/c/chromium/src/+/646754 The follow-up patches will add some modifcations on how we preview username and password suggestions. The suggestions will be in black text, and the password suggestions should be hidden behind dots. Bug: 753645 Tbr: tkent@chromium.org Reviewed-on: https://chromium-review.googlesource.com/702056 Commit-Queue: Sebastien Seguin-Gagnon <sebsg@chromium.org> Reviewed-by: Yoshifumi Inoue <yosin@chromium.org> Reviewed-by: Roger McFarlane <rogerm@chromium.org> Cr-Commit-Position: refs/heads/master@{#509961} (CVE-2018-6037) Change-Id: I3b3ac18726598a3150329d5838d6811d5975d70f Reviewed-by: Michael BrĂ¼ning <michael.bruning@qt.io>
-rw-r--r--chromium/third_party/WebKit/Source/core/css/html.css4
-rw-r--r--chromium/third_party/WebKit/Source/core/html/HTMLInputElement.cpp20
-rw-r--r--chromium/third_party/WebKit/Source/core/html/HTMLInputElement.h9
-rw-r--r--chromium/third_party/WebKit/Source/core/html/HTMLTextAreaElement.cpp24
-rw-r--r--chromium/third_party/WebKit/Source/core/html/HTMLTextAreaElement.h8
-rw-r--r--chromium/third_party/WebKit/Source/core/html/TextControlElement.cpp38
-rw-r--r--chromium/third_party/WebKit/Source/core/html/TextControlElement.h9
-rw-r--r--chromium/third_party/WebKit/Source/core/html/forms/TextFieldInputType.cpp10
8 files changed, 81 insertions, 41 deletions
diff --git a/chromium/third_party/WebKit/Source/core/css/html.css b/chromium/third_party/WebKit/Source/core/css/html.css
index 9e38e56ba59..f571aa22f5c 100644
--- a/chromium/third_party/WebKit/Source/core/css/html.css
+++ b/chromium/third_party/WebKit/Source/core/css/html.css
@@ -522,6 +522,10 @@ input[type="password" i] {
-webkit-text-security: disc !important;
}
+input[type="password" i]::-webkit-input-suggested {
+ -webkit-text-security: disc !important;
+}
+
input[type="hidden" i], input[type="image" i], input[type="file" i] {
-webkit-appearance: initial;
padding: initial;
diff --git a/chromium/third_party/WebKit/Source/core/html/HTMLInputElement.cpp b/chromium/third_party/WebKit/Source/core/html/HTMLInputElement.cpp
index 1784443e4c9..d89d2fe30d8 100644
--- a/chromium/third_party/WebKit/Source/core/html/HTMLInputElement.cpp
+++ b/chromium/third_party/WebKit/Source/core/html/HTMLInputElement.cpp
@@ -1031,15 +1031,11 @@ void HTMLInputElement::SetValueForUser(const String& value) {
setValue(value, kDispatchChangeEvent);
}
-const String& HTMLInputElement::SuggestedValue() const {
- return suggested_value_;
-}
-
void HTMLInputElement::SetSuggestedValue(const String& value) {
if (!input_type_->CanSetSuggestedValue())
return;
needs_to_update_view_value_ = true;
- suggested_value_ = SanitizeValue(value);
+ TextControlElement::SetSuggestedValue(SanitizeValue(value));
SetNeedsStyleRecalc(
kSubtreeStyleChange,
StyleChangeReasonForTracing::Create(StyleChangeReason::kControlValue));
@@ -1083,14 +1079,16 @@ void HTMLInputElement::setValue(const String& value,
if (!input_type_->CanSetValue(value))
return;
+ // Clear the suggested value. Use the base class version to not trigger a view
+ // update.
+ TextControlElement::SetSuggestedValue(String());
+
EventQueueScope scope;
String sanitized_value = SanitizeValue(value);
bool value_changed = sanitized_value != this->value();
SetLastChangeWasNotUserEdit();
needs_to_update_view_value_ = true;
- // Prevent TextFieldInputType::setValue from using the suggested value.
- suggested_value_ = String();
input_type_->SetValue(sanitized_value, value_changed, event_behavior,
selection);
@@ -1162,7 +1160,9 @@ void HTMLInputElement::SetValueFromRenderer(const String& value) {
// File upload controls will never use this.
DCHECK_NE(type(), InputTypeNames::file);
- suggested_value_ = String();
+ // Clear the suggested value. Use the base class version to not trigger a view
+ // update.
+ TextControlElement::SetSuggestedValue(String());
// Renderer and our event handler are responsible for sanitizing values.
DCHECK(value == input_type_->SanitizeUserInputValue(value) ||
@@ -1673,6 +1673,10 @@ void HTMLInputElement::UpdatePlaceholderText() {
return input_type_view_->UpdatePlaceholderText();
}
+String HTMLInputElement::GetPlaceholderValue() const {
+ return !SuggestedValue().IsEmpty() ? SuggestedValue() : StrippedPlaceholder();
+}
+
bool HTMLInputElement::SupportsAutocapitalize() const {
return input_type_->SupportsAutocapitalize();
}
diff --git a/chromium/third_party/WebKit/Source/core/html/HTMLInputElement.h b/chromium/third_party/WebKit/Source/core/html/HTMLInputElement.h
index 31c6ccc8b18..fa18e72b2e5 100644
--- a/chromium/third_party/WebKit/Source/core/html/HTMLInputElement.h
+++ b/chromium/third_party/WebKit/Source/core/html/HTMLInputElement.h
@@ -144,8 +144,7 @@ class CORE_EXPORT HTMLInputElement
String LocalizeValue(const String&) const;
- const String& SuggestedValue() const;
- void SetSuggestedValue(const String&);
+ void SetSuggestedValue(const String& value) override;
void SetEditingValue(const String&);
@@ -297,6 +296,8 @@ class CORE_EXPORT HTMLInputElement
unsigned SizeOfRadioGroup() const;
+ String GetPlaceholderValue() const final;
+
protected:
HTMLInputElement(Document&, bool created_by_parser);
@@ -371,9 +372,6 @@ class CORE_EXPORT HTMLInputElement
bool SupportsPlaceholder() const final;
void UpdatePlaceholderText() final;
bool IsEmptyValue() const final { return InnerEditorValue().IsEmpty(); }
- bool IsEmptySuggestedValue() const final {
- return SuggestedValue().IsEmpty();
- }
void HandleFocusEvent(Element* old_focused_element, WebFocusType) final;
void HandleBlurEvent() final;
void DispatchFocusInEvent(const AtomicString& event_type,
@@ -408,7 +406,6 @@ class CORE_EXPORT HTMLInputElement
AtomicString name_;
// The value string in |value| value mode.
String non_attribute_value_;
- String suggested_value_;
int size_;
// https://html.spec.whatwg.org/multipage/forms.html#concept-input-value-dirty-flag
unsigned has_dirty_value_ : 1;
diff --git a/chromium/third_party/WebKit/Source/core/html/HTMLTextAreaElement.cpp b/chromium/third_party/WebKit/Source/core/html/HTMLTextAreaElement.cpp
index 6e2d9ffa976..1032546cafa 100644
--- a/chromium/third_party/WebKit/Source/core/html/HTMLTextAreaElement.cpp
+++ b/chromium/third_party/WebKit/Source/core/html/HTMLTextAreaElement.cpp
@@ -397,6 +397,10 @@ void HTMLTextAreaElement::SetValueCommon(
normalized_value.Replace("\r\n", "\n");
normalized_value.Replace('\r', '\n');
+ // Clear the suggested value. Use the base class version to not trigger a view
+ // update.
+ TextControlElement::SetSuggestedValue(String());
+
// Return early because we don't want to trigger other side effects when the
// value isn't changing. This is interoperable.
if (normalized_value == value())
@@ -414,7 +418,6 @@ void HTMLTextAreaElement::SetValueCommon(
SetNeedsStyleRecalc(
kSubtreeStyleChange,
StyleChangeReasonForTracing::Create(StyleChangeReason::kControlValue));
- suggested_value_ = String();
SetNeedsValidityCheck();
if (IsFinishedParsingChildren() &&
selection == TextControlSetValueSelection::kSetSelectionToEnd) {
@@ -474,18 +477,8 @@ void HTMLTextAreaElement::setDefaultValue(const String& default_value) {
SetNonDirtyValue(value);
}
-String HTMLTextAreaElement::SuggestedValue() const {
- return suggested_value_;
-}
-
void HTMLTextAreaElement::SetSuggestedValue(const String& value) {
- suggested_value_ = value;
-
- if (!value.IsNull())
- SetInnerEditorValue(suggested_value_);
- else
- SetInnerEditorValue(value_);
- UpdatePlaceholderVisibility();
+ TextControlElement::SetSuggestedValue(value);
SetNeedsStyleRecalc(
kSubtreeStyleChange,
StyleChangeReasonForTracing::Create(StyleChangeReason::kControlValue));
@@ -594,7 +587,7 @@ void HTMLTextAreaElement::SetPlaceholderVisibility(bool visible) {
void HTMLTextAreaElement::UpdatePlaceholderText() {
HTMLElement* placeholder = PlaceholderElement();
- const AtomicString& placeholder_text = FastGetAttribute(placeholderAttr);
+ const String placeholder_text = GetPlaceholderValue();
if (placeholder_text.IsEmpty()) {
if (placeholder)
UserAgentShadowRoot()->RemoveChild(placeholder);
@@ -613,6 +606,11 @@ void HTMLTextAreaElement::UpdatePlaceholderText() {
placeholder->setTextContent(placeholder_text);
}
+String HTMLTextAreaElement::GetPlaceholderValue() const {
+ return !SuggestedValue().IsEmpty() ? SuggestedValue()
+ : FastGetAttribute(placeholderAttr);
+}
+
bool HTMLTextAreaElement::IsInteractiveContent() const {
return true;
}
diff --git a/chromium/third_party/WebKit/Source/core/html/HTMLTextAreaElement.h b/chromium/third_party/WebKit/Source/core/html/HTMLTextAreaElement.h
index 2953a745cba..0d144e0a9d7 100644
--- a/chromium/third_party/WebKit/Source/core/html/HTMLTextAreaElement.h
+++ b/chromium/third_party/WebKit/Source/core/html/HTMLTextAreaElement.h
@@ -52,8 +52,7 @@ class CORE_EXPORT HTMLTextAreaElement final : public TextControlElement {
void setDefaultValue(const String&);
int textLength() const { return value().length(); }
- String SuggestedValue() const;
- void SetSuggestedValue(const String&);
+ void SetSuggestedValue(const String& value) override;
// For ValidityState
String validationMessage() const override;
@@ -87,11 +86,9 @@ class CORE_EXPORT HTMLTextAreaElement final : public TextControlElement {
bool IsPlaceholderVisible() const override { return is_placeholder_visible_; }
void SetPlaceholderVisibility(bool) override;
bool SupportsPlaceholder() const override { return true; }
+ String GetPlaceholderValue() const final;
void UpdatePlaceholderText() override;
bool IsEmptyValue() const override { return value().IsEmpty(); }
- bool IsEmptySuggestedValue() const final {
- return SuggestedValue().IsEmpty();
- }
bool SupportsAutocapitalize() const override { return true; }
const AtomicString& DefaultAutocapitalize() const override;
@@ -148,7 +145,6 @@ class CORE_EXPORT HTMLTextAreaElement final : public TextControlElement {
mutable String value_;
mutable bool is_dirty_;
unsigned is_placeholder_visible_ : 1;
- String suggested_value_;
};
} // namespace blink
diff --git a/chromium/third_party/WebKit/Source/core/html/TextControlElement.cpp b/chromium/third_party/WebKit/Source/core/html/TextControlElement.cpp
index 799d5c4a849..919b188c8c8 100644
--- a/chromium/third_party/WebKit/Source/core/html/TextControlElement.cpp
+++ b/chromium/third_party/WebKit/Source/core/html/TextControlElement.cpp
@@ -42,6 +42,7 @@
#include "core/frame/LocalFrame.h"
#include "core/frame/UseCounter.h"
#include "core/html/HTMLBRElement.h"
+#include "core/html/HTMLDivElement.h"
#include "core/html/parser/HTMLParserIdioms.h"
#include "core/html/shadow/ShadowElementNames.h"
#include "core/layout/LayoutBlock.h"
@@ -155,8 +156,8 @@ bool TextControlElement::IsPlaceholderEmpty() const {
}
bool TextControlElement::PlaceholderShouldBeVisible() const {
- return SupportsPlaceholder() && IsEmptyValue() && IsEmptySuggestedValue() &&
- !IsPlaceholderEmpty();
+ return SupportsPlaceholder() && InnerEditorValue().IsEmpty() &&
+ (!IsPlaceholderEmpty() || !IsEmptySuggestedValue());
}
HTMLElement* TextControlElement::PlaceholderElement() const {
@@ -964,6 +965,39 @@ String TextControlElement::DirectionForFormData() const {
return "ltr";
}
+// TODO(crbug.com/772433): Create and use a new suggested-value element instead.
+void TextControlElement::SetSuggestedValue(const String& value) {
+ suggested_value_ = value;
+ if (!suggested_value_.IsEmpty() && !InnerEditorValue().IsEmpty()) {
+ // Save the value that is in the editor and set the editor value to an empty
+ // string. This will allow the suggestion placeholder to be shown to the
+ // user.
+ value_before_set_suggested_value_ = InnerEditorValue();
+ SetInnerEditorValue("");
+ } else if (suggested_value_.IsEmpty() &&
+ !value_before_set_suggested_value_.IsEmpty()) {
+ // Reset the value that was in the editor before showing the suggestion.
+ SetInnerEditorValue(value_before_set_suggested_value_);
+ value_before_set_suggested_value_ = "";
+ }
+
+ UpdatePlaceholderText();
+
+ HTMLElement* placeholder = PlaceholderElement();
+ if (!placeholder)
+ return;
+
+ // Change the pseudo-id to set the style for suggested values or reset the
+ // placeholder style depending on if there is a suggested value.
+ placeholder->SetShadowPseudoId(AtomicString(suggested_value_.IsEmpty()
+ ? "-webkit-input-placeholder"
+ : "-webkit-input-suggested"));
+}
+
+const String& TextControlElement::SuggestedValue() const {
+ return suggested_value_;
+}
+
HTMLElement* TextControlElement::InnerEditorElement() const {
return ToHTMLElementOrDie(
UserAgentShadowRoot()->getElementById(ShadowElementNames::InnerEditor()));
diff --git a/chromium/third_party/WebKit/Source/core/html/TextControlElement.h b/chromium/third_party/WebKit/Source/core/html/TextControlElement.h
index 536967fcbd9..c8099a5f5e6 100644
--- a/chromium/third_party/WebKit/Source/core/html/TextControlElement.h
+++ b/chromium/third_party/WebKit/Source/core/html/TextControlElement.h
@@ -142,10 +142,14 @@ class CORE_EXPORT TextControlElement : public HTMLFormControlElementWithState {
String DirectionForFormData() const;
+ virtual void SetSuggestedValue(const String& value);
+ const String& SuggestedValue() const;
+
protected:
TextControlElement(const QualifiedName&, Document&);
bool IsPlaceholderEmpty() const;
virtual void UpdatePlaceholderText() = 0;
+ virtual String GetPlaceholderValue() const = 0;
void ParseAttribute(const AttributeModificationParams&) override;
@@ -183,7 +187,7 @@ class CORE_EXPORT TextControlElement : public HTMLFormControlElementWithState {
virtual bool IsEmptyValue() const = 0;
// Returns true if suggested value is empty. Used to check placeholder
// visibility.
- virtual bool IsEmptySuggestedValue() const { return true; }
+ bool IsEmptySuggestedValue() const { return SuggestedValue().IsEmpty(); }
// Called in dispatchFocusEvent(), after placeholder process, before calling
// parent's dispatchFocusEvent().
virtual void HandleFocusEvent(Element* /* oldFocusedNode */, WebFocusType) {}
@@ -203,6 +207,9 @@ class CORE_EXPORT TextControlElement : public HTMLFormControlElementWithState {
unsigned cached_selection_end_;
TextFieldSelectionDirection cached_selection_direction_;
+ String suggested_value_;
+ String value_before_set_suggested_value_;
+
FRIEND_TEST_ALL_PREFIXES(TextControlElementTest, IndexForPosition);
};
diff --git a/chromium/third_party/WebKit/Source/core/html/forms/TextFieldInputType.cpp b/chromium/third_party/WebKit/Source/core/html/forms/TextFieldInputType.cpp
index 5298f3e132e..f31dcbe0753 100644
--- a/chromium/third_party/WebKit/Source/core/html/forms/TextFieldInputType.cpp
+++ b/chromium/third_party/WebKit/Source/core/html/forms/TextFieldInputType.cpp
@@ -466,7 +466,7 @@ void TextFieldInputType::UpdatePlaceholderText() {
if (!SupportsPlaceholder())
return;
HTMLElement* placeholder = GetElement().PlaceholderElement();
- String placeholder_text = GetElement().StrippedPlaceholder();
+ String placeholder_text = GetElement().GetPlaceholderValue();
if (placeholder_text.IsEmpty()) {
if (placeholder)
placeholder->remove(ASSERT_NO_EXCEPTION);
@@ -531,10 +531,10 @@ void TextFieldInputType::SpinButtonStepUp() {
}
void TextFieldInputType::UpdateView() {
- if (!GetElement().SuggestedValue().IsNull()) {
- GetElement().SetInnerEditorValue(GetElement().SuggestedValue());
- GetElement().UpdatePlaceholderVisibility();
- } else if (GetElement().NeedsToUpdateViewValue()) {
+ // The suggested values are now shown using placeholder elements, so there is
+ // nothing to do here for the suggested values.
+ if (GetElement().SuggestedValue().IsEmpty() &&
+ GetElement().NeedsToUpdateViewValue()) {
// Update the view only if needsToUpdateViewValue is true. It protects
// an unacceptable view value from being overwritten with the DOM value.
//