Skip shadow root creation for input types that don't need it

Certain input types like checkboxes and radio buttons don't make use
of the shadow root that is currently created by default. This CL adds
a method to InputTypeView that indicates if an input type needs to
create a shadow root, and skips shadow root creation in
InitializeTypeInParsing if possible.

Bug: 
Change-Id: Id932c06cdd924a5b6006d8770d9cc6d09cb3da82
Reviewed-on: https://chromium-review.googlesource.com/773180
Commit-Queue: Adithya Srinivasan <adithyas@chromium.org>
Reviewed-by: Jeremy Roman <jbroman@chromium.org>
Reviewed-by: Kentaro Hara <haraken@chromium.org>
Reviewed-by: Hayato Ito <hayato@chromium.org>
Reviewed-by: Keishi Hattori <keishi@chromium.org>
Cr-Commit-Position: refs/heads/master@{#518955}
diff --git a/third_party/WebKit/Source/core/html/forms/BaseCheckableInputType.h b/third_party/WebKit/Source/core/html/forms/BaseCheckableInputType.h
index 2e816d6d..28f489f 100644
--- a/third_party/WebKit/Source/core/html/forms/BaseCheckableInputType.h
+++ b/third_party/WebKit/Source/core/html/forms/BaseCheckableInputType.h
@@ -50,6 +50,7 @@
         InputTypeView(element),
         is_in_click_handler_(false) {}
   void HandleKeydownEvent(KeyboardEvent*) override;
+  bool NeedsShadowSubtree() const override { return false; }
 
   bool is_in_click_handler_;
 
diff --git a/third_party/WebKit/Source/core/html/forms/HTMLInputElement.cpp b/third_party/WebKit/Source/core/html/forms/HTMLInputElement.cpp
index 4176b5e..5cbff23 100644
--- a/third_party/WebKit/Source/core/html/forms/HTMLInputElement.cpp
+++ b/third_party/WebKit/Source/core/html/forms/HTMLInputElement.cpp
@@ -124,8 +124,11 @@
                                            bool created_by_parser) {
   HTMLInputElement* input_element =
       new HTMLInputElement(document, created_by_parser);
-  if (!created_by_parser)
-    input_element->EnsureUserAgentShadowRoot();
+  if (!created_by_parser) {
+    DCHECK(input_element->input_type_view_->NeedsShadowSubtree());
+    input_element->CreateUserAgentShadowRoot();
+    input_element->CreateShadowSubtree();
+  }
   return input_element;
 }
 
@@ -147,10 +150,6 @@
   return *image_loader_;
 }
 
-void HTMLInputElement::DidAddUserAgentShadowRoot(ShadowRoot&) {
-  input_type_view_->CreateShadowSubtree();
-}
-
 HTMLInputElement::~HTMLInputElement() {}
 
 const AtomicString& HTMLInputElement::GetName() const {
@@ -375,7 +374,10 @@
   String default_value = FastGetAttribute(valueAttr);
   if (input_type_->GetValueMode() == ValueMode::kValue)
     non_attribute_value_ = SanitizeValue(default_value);
-  EnsureUserAgentShadowRoot();
+  if (input_type_view_->NeedsShadowSubtree()) {
+    CreateUserAgentShadowRoot();
+    CreateShadowSubtree();
+  }
 
   SetNeedsWillValidateCheck();
 
@@ -429,7 +431,10 @@
 
   input_type_ = new_type;
   input_type_view_ = input_type_->CreateView();
-  input_type_view_->CreateShadowSubtree();
+  if (input_type_view_->NeedsShadowSubtree()) {
+    EnsureUserAgentShadowRoot();
+    CreateShadowSubtree();
+  }
 
   SetNeedsWillValidateCheck();
 
@@ -1328,6 +1333,10 @@
     TextControlElement::DefaultEventHandler(evt);
 }
 
+void HTMLInputElement::CreateShadowSubtree() {
+  input_type_view_->CreateShadowSubtree();
+}
+
 bool HTMLInputElement::HasActivationBehavior() const {
   return true;
 }
diff --git a/third_party/WebKit/Source/core/html/forms/HTMLInputElement.h b/third_party/WebKit/Source/core/html/forms/HTMLInputElement.h
index 36f5b32..8c61656 100644
--- a/third_party/WebKit/Source/core/html/forms/HTMLInputElement.h
+++ b/third_party/WebKit/Source/core/html/forms/HTMLInputElement.h
@@ -293,18 +293,18 @@
 
   unsigned SizeOfRadioGroup() const;
 
+  bool SupportsPlaceholder() const final;
   String GetPlaceholderValue() const final;
 
  protected:
   HTMLInputElement(Document&, bool created_by_parser);
 
   void DefaultEventHandler(Event*) override;
+  void CreateShadowSubtree();
 
  private:
   enum AutoCompleteSetting { kUninitialized, kOn, kOff };
 
-  void DidAddUserAgentShadowRoot(ShadowRoot&) final;
-
   void WillChangeForm() final;
   void DidChangeForm() final;
   InsertionNotificationRequest InsertedInto(ContainerNode*) override;
@@ -366,7 +366,6 @@
   bool TooLong(const String&, NeedsToCheckDirtyFlag) const;
   bool TooShort(const String&, NeedsToCheckDirtyFlag) const;
 
-  bool SupportsPlaceholder() const final;
   void UpdatePlaceholderText() final;
   bool IsEmptyValue() const final { return InnerEditorValue().IsEmpty(); }
   void HandleFocusEvent(Element* old_focused_element, WebFocusType) final;
diff --git a/third_party/WebKit/Source/core/html/forms/HTMLInputElementTest.cpp b/third_party/WebKit/Source/core/html/forms/HTMLInputElementTest.cpp
index 822bfb40..3281767 100644
--- a/third_party/WebKit/Source/core/html/forms/HTMLInputElementTest.cpp
+++ b/third_party/WebKit/Source/core/html/forms/HTMLInputElementTest.cpp
@@ -193,4 +193,20 @@
   input->stepDown(1, ASSERT_NO_EXCEPTION);
 }
 
+TEST_F(HTMLInputElementTest, CheckboxHasNoShadowRoot) {
+  GetDocument().body()->SetInnerHTMLFromString("<input type='checkbox' />");
+  HTMLInputElement* input =
+      ToHTMLInputElement(GetDocument().body()->firstChild());
+  EXPECT_EQ(nullptr, input->UserAgentShadowRoot());
+}
+
+TEST_F(HTMLInputElementTest, ChangingInputTypeCausesShadowRootToBeCreated) {
+  GetDocument().body()->SetInnerHTMLFromString("<input type='checkbox' />");
+  HTMLInputElement* input =
+      ToHTMLInputElement(GetDocument().body()->firstChild());
+  EXPECT_EQ(nullptr, input->UserAgentShadowRoot());
+  input->setAttribute(HTMLNames::typeAttr, "text");
+  EXPECT_NE(nullptr, input->UserAgentShadowRoot());
+}
+
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/html/forms/HiddenInputType.h b/third_party/WebKit/Source/core/html/forms/HiddenInputType.h
index 660f1ba..9b8a66d5 100644
--- a/third_party/WebKit/Source/core/html/forms/HiddenInputType.h
+++ b/third_party/WebKit/Source/core/html/forms/HiddenInputType.h
@@ -62,6 +62,7 @@
                 TextFieldEventBehavior,
                 TextControlSetValueSelection) override;
   void AppendToFormData(FormData&) const override;
+  bool NeedsShadowSubtree() const override { return false; }
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/html/forms/InputTypeView.cpp b/third_party/WebKit/Source/core/html/forms/InputTypeView.cpp
index 557d370..1cbd4169 100644
--- a/third_party/WebKit/Source/core/html/forms/InputTypeView.cpp
+++ b/third_party/WebKit/Source/core/html/forms/InputTypeView.cpp
@@ -116,6 +116,10 @@
 
 void InputTypeView::ClosePopupView() {}
 
+bool InputTypeView::NeedsShadowSubtree() const {
+  return true;
+}
+
 void InputTypeView::CreateShadowSubtree() {}
 
 void InputTypeView::DestroyShadowSubtree() {
diff --git a/third_party/WebKit/Source/core/html/forms/InputTypeView.h b/third_party/WebKit/Source/core/html/forms/InputTypeView.h
index 6d000b4..8c256add 100644
--- a/third_party/WebKit/Source/core/html/forms/InputTypeView.h
+++ b/third_party/WebKit/Source/core/html/forms/InputTypeView.h
@@ -104,6 +104,7 @@
   virtual TextDirection ComputedTextDirection();
   virtual void StartResourceLoading();
   virtual void ClosePopupView();
+  virtual bool NeedsShadowSubtree() const;
   virtual void CreateShadowSubtree();
   virtual void DestroyShadowSubtree();
   virtual void MinOrMaxAttributeChanged();
diff --git a/third_party/WebKit/Source/core/html/forms/TextControlElement.cpp b/third_party/WebKit/Source/core/html/forms/TextControlElement.cpp
index 8ac8685..790dc1e0 100644
--- a/third_party/WebKit/Source/core/html/forms/TextControlElement.cpp
+++ b/third_party/WebKit/Source/core/html/forms/TextControlElement.cpp
@@ -166,6 +166,9 @@
 }
 
 HTMLElement* TextControlElement::PlaceholderElement() const {
+  if (!SupportsPlaceholder())
+    return nullptr;
+  DCHECK(UserAgentShadowRoot());
   return ToHTMLElementOrDie(
       UserAgentShadowRoot()->getElementById(ShadowElementNames::Placeholder()));
 }
@@ -807,6 +810,8 @@
   if (!IsTextControl() || OpenShadowRoot())
     return;
 
+  DCHECK(InnerEditorElement());
+
   bool text_is_changed = value != InnerEditorValue();
   HTMLElement* inner_editor = InnerEditorElement();
   if (!text_is_changed && inner_editor->HasChildren())
diff --git a/third_party/WebKit/Source/modules/accessibility/AXLayoutObject.cpp b/third_party/WebKit/Source/modules/accessibility/AXLayoutObject.cpp
index 50afdbe..937c80f 100644
--- a/third_party/WebKit/Source/modules/accessibility/AXLayoutObject.cpp
+++ b/third_party/WebKit/Source/modules/accessibility/AXLayoutObject.cpp
@@ -2495,8 +2495,10 @@
     return;
 
   HTMLInputElement& input = ToHTMLInputElement(*node);
-  Element* spin_button_element = input.UserAgentShadowRoot()->getElementById(
-      ShadowElementNames::SpinButton());
+  Element* spin_button_element =
+      input.UserAgentShadowRoot() ? input.UserAgentShadowRoot()->getElementById(
+                                        ShadowElementNames::SpinButton())
+                                  : nullptr;
   if (!spin_button_element || !spin_button_element->IsSpinButtonElement())
     return;
 
diff --git a/third_party/WebKit/Source/modules/media_controls/elements/MediaControlCastButtonElement.cpp b/third_party/WebKit/Source/modules/media_controls/elements/MediaControlCastButtonElement.cpp
index ddf0ab1..507e28f4 100644
--- a/third_party/WebKit/Source/modules/media_controls/elements/MediaControlCastButtonElement.cpp
+++ b/third_party/WebKit/Source/modules/media_controls/elements/MediaControlCastButtonElement.cpp
@@ -35,7 +35,6 @@
     bool is_overlay_button)
     : MediaControlInputElement(media_controls, kMediaCastOnButton),
       is_overlay_button_(is_overlay_button) {
-  EnsureUserAgentShadowRoot();
   SetShadowPseudoId(is_overlay_button
                         ? "-internal-media-controls-overlay-cast-button"
                         : "-internal-media-controls-cast-button");
diff --git a/third_party/WebKit/Source/modules/media_controls/elements/MediaControlDownloadButtonElement.cpp b/third_party/WebKit/Source/modules/media_controls/elements/MediaControlDownloadButtonElement.cpp
index fd328b0..f5bd537 100644
--- a/third_party/WebKit/Source/modules/media_controls/elements/MediaControlDownloadButtonElement.cpp
+++ b/third_party/WebKit/Source/modules/media_controls/elements/MediaControlDownloadButtonElement.cpp
@@ -21,7 +21,6 @@
 MediaControlDownloadButtonElement::MediaControlDownloadButtonElement(
     MediaControlsImpl& media_controls)
     : MediaControlInputElement(media_controls, kMediaDownloadButton) {
-  EnsureUserAgentShadowRoot();
   setType(InputTypeNames::button);
   SetShadowPseudoId(AtomicString("-internal-media-controls-download-button"));
   SetIsWanted(false);
diff --git a/third_party/WebKit/Source/modules/media_controls/elements/MediaControlFullscreenButtonElement.cpp b/third_party/WebKit/Source/modules/media_controls/elements/MediaControlFullscreenButtonElement.cpp
index 82c8d987e..ac5b2de8 100644
--- a/third_party/WebKit/Source/modules/media_controls/elements/MediaControlFullscreenButtonElement.cpp
+++ b/third_party/WebKit/Source/modules/media_controls/elements/MediaControlFullscreenButtonElement.cpp
@@ -16,7 +16,6 @@
 MediaControlFullscreenButtonElement::MediaControlFullscreenButtonElement(
     MediaControlsImpl& media_controls)
     : MediaControlInputElement(media_controls, kMediaEnterFullscreenButton) {
-  EnsureUserAgentShadowRoot();
   setType(InputTypeNames::button);
   SetShadowPseudoId(AtomicString("-webkit-media-controls-fullscreen-button"));
   SetIsFullscreen(MediaElement().IsFullscreen());
diff --git a/third_party/WebKit/Source/modules/media_controls/elements/MediaControlInputElement.cpp b/third_party/WebKit/Source/modules/media_controls/elements/MediaControlInputElement.cpp
index a6f6931..42cffce 100644
--- a/third_party/WebKit/Source/modules/media_controls/elements/MediaControlInputElement.cpp
+++ b/third_party/WebKit/Source/modules/media_controls/elements/MediaControlInputElement.cpp
@@ -112,7 +112,10 @@
     MediaControlsImpl& media_controls,
     MediaControlElementType display_type)
     : HTMLInputElement(media_controls.GetDocument(), false),
-      MediaControlElementBase(media_controls, display_type, this) {}
+      MediaControlElementBase(media_controls, display_type, this) {
+  CreateUserAgentShadowRoot();
+  CreateShadowSubtree();
+}
 
 WebLocalizedString::Name MediaControlInputElement::GetOverflowStringName()
     const {
diff --git a/third_party/WebKit/Source/modules/media_controls/elements/MediaControlInputElementTest.cpp b/third_party/WebKit/Source/modules/media_controls/elements/MediaControlInputElementTest.cpp
index 4363ff8..bb46bfa1 100644
--- a/third_party/WebKit/Source/modules/media_controls/elements/MediaControlInputElementTest.cpp
+++ b/third_party/WebKit/Source/modules/media_controls/elements/MediaControlInputElementTest.cpp
@@ -29,7 +29,6 @@
   MediaControlInputElementImpl(MediaControlsImpl& media_controls)
       // Using arbitrary MediaControlElementType. It should have no impact.
       : MediaControlInputElement(media_controls, kMediaDownloadButton) {
-    EnsureUserAgentShadowRoot();
     setType(InputTypeNames::button);
     SetIsWanted(false);
   }
diff --git a/third_party/WebKit/Source/modules/media_controls/elements/MediaControlMuteButtonElement.cpp b/third_party/WebKit/Source/modules/media_controls/elements/MediaControlMuteButtonElement.cpp
index 371225e..c021d84 100644
--- a/third_party/WebKit/Source/modules/media_controls/elements/MediaControlMuteButtonElement.cpp
+++ b/third_party/WebKit/Source/modules/media_controls/elements/MediaControlMuteButtonElement.cpp
@@ -15,7 +15,6 @@
 MediaControlMuteButtonElement::MediaControlMuteButtonElement(
     MediaControlsImpl& media_controls)
     : MediaControlInputElement(media_controls, kMediaMuteButton) {
-  EnsureUserAgentShadowRoot();
   setType(InputTypeNames::button);
   SetShadowPseudoId(AtomicString("-webkit-media-controls-mute-button"));
 }
diff --git a/third_party/WebKit/Source/modules/media_controls/elements/MediaControlOverflowMenuButtonElement.cpp b/third_party/WebKit/Source/modules/media_controls/elements/MediaControlOverflowMenuButtonElement.cpp
index 04e4f64..7da7b78 100644
--- a/third_party/WebKit/Source/modules/media_controls/elements/MediaControlOverflowMenuButtonElement.cpp
+++ b/third_party/WebKit/Source/modules/media_controls/elements/MediaControlOverflowMenuButtonElement.cpp
@@ -14,7 +14,6 @@
 MediaControlOverflowMenuButtonElement::MediaControlOverflowMenuButtonElement(
     MediaControlsImpl& media_controls)
     : MediaControlInputElement(media_controls, kMediaOverflowButton) {
-  EnsureUserAgentShadowRoot();
   setType(InputTypeNames::button);
   SetShadowPseudoId(AtomicString("-internal-media-controls-overflow-button"));
   SetIsWanted(false);
diff --git a/third_party/WebKit/Source/modules/media_controls/elements/MediaControlOverlayPlayButtonElement.cpp b/third_party/WebKit/Source/modules/media_controls/elements/MediaControlOverlayPlayButtonElement.cpp
index bc5f4331..2b43094 100644
--- a/third_party/WebKit/Source/modules/media_controls/elements/MediaControlOverlayPlayButtonElement.cpp
+++ b/third_party/WebKit/Source/modules/media_controls/elements/MediaControlOverlayPlayButtonElement.cpp
@@ -35,7 +35,6 @@
     MediaControlsImpl& media_controls)
     : MediaControlInputElement(media_controls, kMediaOverlayPlayButton),
       internal_button_(nullptr) {
-  EnsureUserAgentShadowRoot();
   setType(InputTypeNames::button);
   SetShadowPseudoId(AtomicString("-webkit-media-controls-overlay-play-button"));
 
diff --git a/third_party/WebKit/Source/modules/media_controls/elements/MediaControlPlayButtonElement.cpp b/third_party/WebKit/Source/modules/media_controls/elements/MediaControlPlayButtonElement.cpp
index a13802b..beb6c5e 100644
--- a/third_party/WebKit/Source/modules/media_controls/elements/MediaControlPlayButtonElement.cpp
+++ b/third_party/WebKit/Source/modules/media_controls/elements/MediaControlPlayButtonElement.cpp
@@ -16,7 +16,6 @@
 MediaControlPlayButtonElement::MediaControlPlayButtonElement(
     MediaControlsImpl& media_controls)
     : MediaControlInputElement(media_controls, kMediaPlayButton) {
-  EnsureUserAgentShadowRoot();
   setType(InputTypeNames::button);
   SetShadowPseudoId(AtomicString("-webkit-media-controls-play-button"));
 }
diff --git a/third_party/WebKit/Source/modules/media_controls/elements/MediaControlSliderElement.cpp b/third_party/WebKit/Source/modules/media_controls/elements/MediaControlSliderElement.cpp
index 678601b0..8e908ce0 100644
--- a/third_party/WebKit/Source/modules/media_controls/elements/MediaControlSliderElement.cpp
+++ b/third_party/WebKit/Source/modules/media_controls/elements/MediaControlSliderElement.cpp
@@ -73,7 +73,6 @@
       resize_observer_(ResizeObserver::Create(
           GetDocument(),
           new MediaControlSliderElementResizeObserverDelegate(this))) {
-  EnsureUserAgentShadowRoot();
   setType(InputTypeNames::range);
   setAttribute(HTMLNames::stepAttr, "any");
   resize_observer_->observe(this);
diff --git a/third_party/WebKit/Source/modules/media_controls/elements/MediaControlToggleClosedCaptionsButtonElement.cpp b/third_party/WebKit/Source/modules/media_controls/elements/MediaControlToggleClosedCaptionsButtonElement.cpp
index 51335e3..a2664473 100644
--- a/third_party/WebKit/Source/modules/media_controls/elements/MediaControlToggleClosedCaptionsButtonElement.cpp
+++ b/third_party/WebKit/Source/modules/media_controls/elements/MediaControlToggleClosedCaptionsButtonElement.cpp
@@ -16,7 +16,6 @@
     MediaControlToggleClosedCaptionsButtonElement(
         MediaControlsImpl& media_controls)
     : MediaControlInputElement(media_controls, kMediaShowClosedCaptionsButton) {
-  EnsureUserAgentShadowRoot();
   setType(InputTypeNames::button);
   SetShadowPseudoId(
       AtomicString("-webkit-media-controls-toggle-closed-captions-button"));