Commit 79da0963 authored by Yao Xiao's avatar Yao Xiao Committed by Commit Bot

Move the email regex from HTMLInputElement to DocumentData

This reduces the overall memory. And hopefully it could fix the
regression introduced by
https://chromium-review.googlesource.com/c/chromium/src/+/2324204,
which could allocate a regex for every input element.

Bug: 1116302
Change-Id: I00f1fa7ad07664d5ab799e760483034c1a1594fe
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2357464
Commit-Queue: Yao Xiao <yaoxia@chromium.org>
Reviewed-by: default avatarMason Freed <masonfreed@chromium.org>
Cr-Commit-Position: refs/heads/master@{#802754}
parent d3ec1564
......@@ -198,6 +198,7 @@
#include "third_party/blink/renderer/core/html/custom/v0_custom_element_registration_context.h"
#include "third_party/blink/renderer/core/html/document_all_name_collection.h"
#include "third_party/blink/renderer/core/html/document_name_collection.h"
#include "third_party/blink/renderer/core/html/forms/email_input_type.h"
#include "third_party/blink/renderer/core/html/forms/form_controller.h"
#include "third_party/blink/renderer/core/html/forms/html_form_element.h"
#include "third_party/blink/renderer/core/html/forms/html_input_element.h"
......@@ -7301,6 +7302,12 @@ Document::EnsureDocumentExplicitRootIntersectionObserverData() {
return *document_explicit_root_intersection_observer_data_;
}
const ScriptRegexp& Document::EnsureEmailRegexp() const {
if (!data_->email_regexp_)
data_->email_regexp_ = EmailInputType::CreateEmailRegexp();
return *data_->email_regexp_;
}
void Document::AddConsoleMessage(ConsoleMessage* message,
bool discard_duplicates) const {
// Don't let non-attached Documents spam the console.
......
......@@ -188,6 +188,7 @@ class Text;
class TrustedHTML;
class ScriptElementBase;
class ScriptPromise;
class ScriptRegexp;
class ScriptRunner;
class ScriptableDocumentParser;
class ScriptedAnimationController;
......@@ -986,6 +987,8 @@ class CORE_EXPORT Document : public ContainerNode,
ElementIntersectionObserverData&
EnsureDocumentExplicitRootIntersectionObserverData();
const ScriptRegexp& EnsureEmailRegexp() const;
// Returns the owning element in the parent document. Returns nullptr if
// this is the top level document or the owner is remote.
HTMLFrameOwnerElement* LocalOwner() const;
......
......@@ -7,6 +7,7 @@
#include "services/network/public/mojom/trust_tokens.mojom-blink.h"
#include "third_party/blink/public/mojom/permissions/permission.mojom-blink.h"
#include "third_party/blink/renderer/bindings/core/v8/script_regexp.h"
#include "third_party/blink/renderer/platform/mojo/heap_mojo_remote.h"
namespace blink {
......@@ -19,7 +20,7 @@ namespace blink {
// Other instances should not have strong references to the DocumentData.
// Lifetime: A DocumentData instance is created on a Document creation, and
// is never destructed before the Document.
class DocumentData : public GarbageCollected<DocumentData> {
class DocumentData final : public GarbageCollected<DocumentData> {
public:
explicit DocumentData(ExecutionContext* context)
: permission_service_(context), has_trust_tokens_answerer_(context) {}
......@@ -51,6 +52,9 @@ class DocumentData : public GarbageCollected<DocumentData> {
HeapHashSet<Member<ScriptPromiseResolver>>
pending_has_trust_tokens_resolvers_;
// To do email regex checks.
std::unique_ptr<ScriptRegexp> email_regexp_;
friend class Document;
};
......
......@@ -175,24 +175,25 @@ const AtomicString& EmailInputType::FormControlType() const {
return input_type_names::kEmail;
}
ScriptRegexp& EmailInputType::EnsureEmailRegexp() const {
return GetElement().EnsureEmailRegexp();
}
// The return value is an invalid email address string if the specified string
// contains an invalid email address. Otherwise, null string is returned.
// contains an invalid email address. Otherwise, an empty string is returned.
// If an empty string is returned, it means empty address is specified.
// e.g. "foo@example.com,,bar@example.com" for multiple case.
String EmailInputType::FindInvalidAddress(const String& value) const {
if (value.IsEmpty())
return String();
if (!GetElement().Multiple())
return IsValidEmailAddress(EnsureEmailRegexp(), value) ? String() : value;
if (!GetElement().Multiple()) {
return IsValidEmailAddress(GetElement().GetDocument().EnsureEmailRegexp(),
value)
? String()
: value;
}
Vector<String> addresses;
value.Split(',', true, addresses);
for (const auto& address : addresses) {
String stripped = StripLeadingAndTrailingHTMLSpaces(address);
if (!IsValidEmailAddress(EnsureEmailRegexp(), stripped))
if (!IsValidEmailAddress(GetElement().GetDocument().EnsureEmailRegexp(),
stripped))
return stripped;
}
return String();
......@@ -282,8 +283,10 @@ String EmailInputType::SanitizeValue(const String& proposed_value) const {
String EmailInputType::ConvertFromVisibleValue(
const String& visible_value) const {
String sanitized_value = SanitizeValue(visible_value);
if (!GetElement().Multiple())
return ConvertEmailAddressToASCII(EnsureEmailRegexp(), sanitized_value);
if (!GetElement().Multiple()) {
return ConvertEmailAddressToASCII(
GetElement().GetDocument().EnsureEmailRegexp(), sanitized_value);
}
Vector<String> addresses;
sanitized_value.Split(',', true, addresses);
StringBuilder builder;
......@@ -291,8 +294,8 @@ String EmailInputType::ConvertFromVisibleValue(
for (wtf_size_t i = 0; i < addresses.size(); ++i) {
if (i > 0)
builder.Append(',');
builder.Append(
ConvertEmailAddressToASCII(EnsureEmailRegexp(), addresses[i]));
builder.Append(ConvertEmailAddressToASCII(
GetElement().GetDocument().EnsureEmailRegexp(), addresses[i]));
}
return builder.ToString();
}
......
......@@ -57,7 +57,6 @@ class EmailInputType final : public BaseTextInputType {
String ConvertFromVisibleValue(const String&) const override;
String VisibleValue() const override;
ScriptRegexp& EnsureEmailRegexp() const;
String ConvertEmailAddressToUnicode(const String&) const;
String FindInvalidAddress(const String&) const;
};
......
......@@ -2030,12 +2030,6 @@ bool HTMLInputElement::IsDraggedSlider() const {
return input_type_view_->IsDraggedSlider();
}
ScriptRegexp& HTMLInputElement::EnsureEmailRegexp() const {
if (!email_regexp_)
email_regexp_ = EmailInputType::CreateEmailRegexp();
return *email_regexp_;
}
void HTMLInputElement::MaybeReportPiiMetrics() {
// Don't report metrics if the field is empty.
if (value().IsEmpty())
......@@ -2061,7 +2055,8 @@ void HTMLInputElement::MaybeReportPiiMetrics() {
// https://www.rfc-editor.org/errata_search.php?rfc=3696) in addition to
// matching with the pattern given by the HTML standard.
if (value().length() <= kMaxEmailFieldLength &&
EmailInputType::IsValidEmailAddress(EnsureEmailRegexp(), value())) {
EmailInputType::IsValidEmailAddress(GetDocument().EnsureEmailRegexp(),
value())) {
UseCounter::Count(GetDocument(),
WebFeature::kEmailFieldDetected_PatternMatch);
}
......
......@@ -347,8 +347,6 @@ class CORE_EXPORT HTMLInputElement
form_element_pii_type_ = form_element_pii_type;
}
ScriptRegexp& EnsureEmailRegexp() const;
protected:
void DefaultEventHandler(Event&) override;
void CreateShadowSubtree();
......@@ -478,7 +476,6 @@ class CORE_EXPORT HTMLInputElement
Member<ListAttributeTargetObserver> list_attribute_target_observer_;
FormElementPiiType form_element_pii_type_ = FormElementPiiType::kUnknown;
mutable std::unique_ptr<ScriptRegexp> email_regexp_;
FRIEND_TEST_ALL_PREFIXES(HTMLInputElementTest, RadioKeyDownDCHECKFailure);
};
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment