Commit f8224e8c authored by Kent Tamura's avatar Kent Tamura Committed by Commit Bot

Add a shadow element to each of menulist SELECTs

This CL introduces blink::MenuListInnerElement, which will replace the
anonymous block in LayoutMenuList. For now, we just add the element to
UA shadow tree with display:none. So this CL doesn't have any changes
on SELECT rendering.

* UpdateUserAgentShadowTree()
 Add MenuListInnerElement as the first child of ShadowRoot
 if UsesMenuList().
 Otherwise, remove it from the UA shadow tree.

* Update some test expectations for the new shadow element.

Bug: 1040828
Change-Id: I6c59c45dcc41baa41ff0e0ab060c14c2eefb6cff
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2032645Reviewed-by: default avatarKoji Ishii <kojii@chromium.org>
Commit-Queue: Kent Tamura <tkent@chromium.org>
Cr-Commit-Position: refs/heads/master@{#737248}
parent 10dc9c96
...@@ -391,6 +391,7 @@ TEST_P(ParameterizedTextOffsetMappingTest, RangeWithNestedPosition) { ...@@ -391,6 +391,7 @@ TEST_P(ParameterizedTextOffsetMappingTest, RangeWithNestedPosition) {
TEST_P(ParameterizedTextOffsetMappingTest, RangeWithSelect) { TEST_P(ParameterizedTextOffsetMappingTest, RangeWithSelect) {
EXPECT_EQ( EXPECT_EQ(
"^<select>" "^<select>"
"<div></div>"
"<slot name=\"user-agent-custom-assign-slot\"></slot>" "<slot name=\"user-agent-custom-assign-slot\"></slot>"
"</select>foo|", "</select>foo|",
GetRange("<select>|</select>foo")); GetRange("<select>|</select>foo"));
......
...@@ -220,6 +220,8 @@ blink_core_sources("html") { ...@@ -220,6 +220,8 @@ blink_core_sources("html") {
"forms/labels_node_list.h", "forms/labels_node_list.h",
"forms/listed_element.cc", "forms/listed_element.cc",
"forms/listed_element.h", "forms/listed_element.h",
"forms/menu_list_inner_element.cc",
"forms/menu_list_inner_element.h",
"forms/month_input_type.cc", "forms/month_input_type.cc",
"forms/month_input_type.h", "forms/month_input_type.h",
"forms/multiple_fields_temporal_input_type_view.cc", "forms/multiple_fields_temporal_input_type_view.cc",
......
...@@ -58,6 +58,7 @@ ...@@ -58,6 +58,7 @@
#include "third_party/blink/renderer/core/html/forms/html_form_element.h" #include "third_party/blink/renderer/core/html/forms/html_form_element.h"
#include "third_party/blink/renderer/core/html/forms/html_opt_group_element.h" #include "third_party/blink/renderer/core/html/forms/html_opt_group_element.h"
#include "third_party/blink/renderer/core/html/forms/html_option_element.h" #include "third_party/blink/renderer/core/html/forms/html_option_element.h"
#include "third_party/blink/renderer/core/html/forms/menu_list_inner_element.h"
#include "third_party/blink/renderer/core/html/forms/popup_menu.h" #include "third_party/blink/renderer/core/html/forms/popup_menu.h"
#include "third_party/blink/renderer/core/html/html_hr_element.h" #include "third_party/blink/renderer/core/html/html_hr_element.h"
#include "third_party/blink/renderer/core/html/html_slot_element.h" #include "third_party/blink/renderer/core/html/html_slot_element.h"
...@@ -317,6 +318,7 @@ void HTMLSelectElement::ParseAttribute( ...@@ -317,6 +318,7 @@ void HTMLSelectElement::ParseAttribute(
if (size_ != old_size) { if (size_ != old_size) {
ChangeRendering(); ChangeRendering();
ResetToDefaultSelection(); ResetToDefaultSelection();
UpdateUserAgentShadowTree(*UserAgentShadowRoot());
if (!UsesMenuList()) if (!UsesMenuList())
SaveListboxActiveSelection(); SaveListboxActiveSelection();
} }
...@@ -1283,6 +1285,7 @@ void HTMLSelectElement::ParseMultipleAttribute(const AtomicString& value) { ...@@ -1283,6 +1285,7 @@ void HTMLSelectElement::ParseMultipleAttribute(const AtomicString& value) {
else else
ResetToDefaultSelection(); ResetToDefaultSelection();
} }
UpdateUserAgentShadowTree(*UserAgentShadowRoot());
} }
void HTMLSelectElement::AppendToFormData(FormData& form_data) { void HTMLSelectElement::AppendToFormData(FormData& form_data) {
...@@ -1983,8 +1986,37 @@ void HTMLSelectElement::Trace(Visitor* visitor) { ...@@ -1983,8 +1986,37 @@ void HTMLSelectElement::Trace(Visitor* visitor) {
} }
void HTMLSelectElement::DidAddUserAgentShadowRoot(ShadowRoot& root) { void HTMLSelectElement::DidAddUserAgentShadowRoot(ShadowRoot& root) {
// Even if UsesMenuList(), the <slot> is necessary to have ComputedStyles
// for <option>s. LayoutMenuList::IsChildAllowed() rejects all of
// LayoutObject children except for MenuListInnerElement's.
root.AppendChild( root.AppendChild(
HTMLSlotElement::CreateUserAgentCustomAssignSlot(GetDocument())); HTMLSlotElement::CreateUserAgentCustomAssignSlot(GetDocument()));
UpdateUserAgentShadowTree(root);
}
void HTMLSelectElement::UpdateUserAgentShadowTree(ShadowRoot& root) {
// Remove all children of the ShadowRoot except for <slot>.
Node* node = root.firstChild();
while (node) {
if (IsA<HTMLSlotElement>(node)) {
node = node->nextSibling();
} else {
auto* will_be_removed = node;
node = node->nextSibling();
will_be_removed->remove();
}
}
if (UsesMenuList()) {
root.insertBefore(MakeGarbageCollected<MenuListInnerElement>(GetDocument()),
root.firstChild());
}
}
Element& HTMLSelectElement::InnerElement() const {
DCHECK(UsesMenuList());
auto* inner_element = DynamicTo<Element>(UserAgentShadowRoot()->firstChild());
DCHECK(inner_element);
return *inner_element;
} }
HTMLOptionElement* HTMLSelectElement::SpatialNavigationFocusedOption() { HTMLOptionElement* HTMLSelectElement::SpatialNavigationFocusedOption() {
......
...@@ -181,6 +181,9 @@ class CORE_EXPORT HTMLSelectElement final ...@@ -181,6 +181,9 @@ class CORE_EXPORT HTMLSelectElement final
void CloneNonAttributePropertiesFrom(const Element&, void CloneNonAttributePropertiesFrom(const Element&,
CloneChildrenFlag) override; CloneChildrenFlag) override;
// This should be called only if UsesMenuList().
Element& InnerElement() const;
private: private:
const AtomicString& FormControlType() const override; const AtomicString& FormControlType() const override;
void UpdateFromElement(); void UpdateFromElement();
...@@ -299,6 +302,7 @@ class CORE_EXPORT HTMLSelectElement final ...@@ -299,6 +302,7 @@ class CORE_EXPORT HTMLSelectElement final
// Apply changes to rendering as a result of attribute changes (multiple, // Apply changes to rendering as a result of attribute changes (multiple,
// size). // size).
void ChangeRendering(); void ChangeRendering();
void UpdateUserAgentShadowTree(ShadowRoot& root);
// list_items_ contains HTMLOptionElement, HTMLOptGroupElement, and // list_items_ contains HTMLOptionElement, HTMLOptGroupElement, and
// HTMLHRElement objects. // HTMLHRElement objects.
......
// Copyright 2020 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.
#include "third_party/blink/renderer/core/html/forms/menu_list_inner_element.h"
#include "third_party/blink/renderer/core/dom/node_computed_style.h"
#include "third_party/blink/renderer/core/style/computed_style.h"
namespace blink {
MenuListInnerElement::MenuListInnerElement(Document& document)
: HTMLDivElement(document) {
SetHasCustomStyleCallbacks();
}
scoped_refptr<ComputedStyle>
MenuListInnerElement::CustomStyleForLayoutObject() {
const ComputedStyle& parent_style = OwnerShadowHost()->ComputedStyleRef();
scoped_refptr<ComputedStyle> style =
ComputedStyle::CreateAnonymousStyleWithDisplay(parent_style,
EDisplay::kNone);
return style;
}
} // namespace blink
// Copyright 2020 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.
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_HTML_FORMS_MENU_LIST_INNER_ELEMENT_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_HTML_FORMS_MENU_LIST_INNER_ELEMENT_H_
#include "third_party/blink/renderer/core/html/html_div_element.h"
namespace blink {
class MenuListInnerElement : public HTMLDivElement {
public:
explicit MenuListInnerElement(Document& document);
private:
scoped_refptr<ComputedStyle> CustomStyleForLayoutObject() override;
};
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_CORE_HTML_FORMS_MENU_LIST_INNER_ELEMENT_H_
...@@ -64,6 +64,7 @@ Input before setting suggested values: ...@@ -64,6 +64,7 @@ Input before setting suggested values:
| <shadow:root> | <shadow:root>
| "TX" | "TX"
| <shadow:root> | <shadow:root>
| <div>
| <slot> | <slot>
| name="user-agent-custom-assign-slot" | name="user-agent-custom-assign-slot"
| "input.value: initial value" | "input.value: initial value"
...@@ -153,6 +154,7 @@ Input after setting suggestedValue: ...@@ -153,6 +154,7 @@ Input after setting suggestedValue:
| <shadow:root> | <shadow:root>
| "TX" | "TX"
| <shadow:root> | <shadow:root>
| <div>
| <slot> | <slot>
| name="user-agent-custom-assign-slot" | name="user-agent-custom-assign-slot"
| "input.value: initial value" | "input.value: initial value"
...@@ -240,6 +242,7 @@ After resetting suggestedValue value: ...@@ -240,6 +242,7 @@ After resetting suggestedValue value:
| <shadow:root> | <shadow:root>
| "TX" | "TX"
| <shadow:root> | <shadow:root>
| <div>
| <slot> | <slot>
| name="user-agent-custom-assign-slot" | name="user-agent-custom-assign-slot"
| "input.value: initial value" | "input.value: initial value"
......
...@@ -90,6 +90,7 @@ instead of "initial value". ...@@ -90,6 +90,7 @@ instead of "initial value".
| <shadow:root> | <shadow:root>
| "inserted value" | "inserted value"
| <shadow:root> | <shadow:root>
| <div>
| <slot> | <slot>
| name="user-agent-custom-assign-slot" | name="user-agent-custom-assign-slot"
| "input.value: initial value" | "input.value: initial value"
......
...@@ -43,7 +43,7 @@ Tests DOMSnapshot.getSnapshot method returning input values. ...@@ -43,7 +43,7 @@ Tests DOMSnapshot.getSnapshot method returning input values.
"childNodeIndexes": [ "childNodeIndexes": [
4, 4,
5, 5,
33 34
], ],
"attributes": [ "attributes": [
{ {
...@@ -67,11 +67,10 @@ Tests DOMSnapshot.getSnapshot method returning input values. ...@@ -67,11 +67,10 @@ Tests DOMSnapshot.getSnapshot method returning input values.
"childNodeIndexes": [ "childNodeIndexes": [
6, 6,
7, 7,
13,
14, 14,
17, 15,
18, 18,
20, 19,
21, 21,
22, 22,
23, 23,
...@@ -81,7 +80,8 @@ Tests DOMSnapshot.getSnapshot method returning input values. ...@@ -81,7 +80,8 @@ Tests DOMSnapshot.getSnapshot method returning input values.
27, 27,
28, 28,
29, 29,
32 30,
33
], ],
"attributes": [ "attributes": [
{ {
...@@ -103,18 +103,26 @@ Tests DOMSnapshot.getSnapshot method returning input values. ...@@ -103,18 +103,26 @@ Tests DOMSnapshot.getSnapshot method returning input values.
"nodeValue": "", "nodeValue": "",
"backendNodeId": "<number>", "backendNodeId": "<number>",
"childNodeIndexes": [ "childNodeIndexes": [
8 8,
9
], ],
"layoutNodeIndex": 4 "layoutNodeIndex": 4
}, },
{
"nodeType": 1,
"nodeName": "DIV",
"nodeValue": "",
"backendNodeId": "<number>",
"shadowRootType": "user-agent"
},
{ {
"nodeType": 1, "nodeType": 1,
"nodeName": "SLOT", "nodeName": "SLOT",
"nodeValue": "", "nodeValue": "",
"backendNodeId": "<number>", "backendNodeId": "<number>",
"childNodeIndexes": [ "childNodeIndexes": [
9, 10,
11 12
], ],
"attributes": [ "attributes": [
{ {
...@@ -131,7 +139,7 @@ Tests DOMSnapshot.getSnapshot method returning input values. ...@@ -131,7 +139,7 @@ Tests DOMSnapshot.getSnapshot method returning input values.
"optionSelected": true, "optionSelected": true,
"backendNodeId": "<number>", "backendNodeId": "<number>",
"childNodeIndexes": [ "childNodeIndexes": [
10 11
], ],
"attributes": [ "attributes": [
{ {
...@@ -154,7 +162,7 @@ Tests DOMSnapshot.getSnapshot method returning input values. ...@@ -154,7 +162,7 @@ Tests DOMSnapshot.getSnapshot method returning input values.
"optionSelected": false, "optionSelected": false,
"backendNodeId": "<number>", "backendNodeId": "<number>",
"childNodeIndexes": [ "childNodeIndexes": [
12 13
], ],
"attributes": [ "attributes": [
{ {
...@@ -184,7 +192,7 @@ Tests DOMSnapshot.getSnapshot method returning input values. ...@@ -184,7 +192,7 @@ Tests DOMSnapshot.getSnapshot method returning input values.
"inputValue": "InputValue", "inputValue": "InputValue",
"backendNodeId": "<number>", "backendNodeId": "<number>",
"childNodeIndexes": [ "childNodeIndexes": [
15 16
], ],
"attributes": [ "attributes": [
{ {
...@@ -205,7 +213,7 @@ Tests DOMSnapshot.getSnapshot method returning input values. ...@@ -205,7 +213,7 @@ Tests DOMSnapshot.getSnapshot method returning input values.
"nodeValue": "", "nodeValue": "",
"backendNodeId": "<number>", "backendNodeId": "<number>",
"childNodeIndexes": [ "childNodeIndexes": [
16 17
], ],
"layoutNodeIndex": 7, "layoutNodeIndex": 7,
"shadowRootType": "user-agent", "shadowRootType": "user-agent",
...@@ -234,7 +242,7 @@ Tests DOMSnapshot.getSnapshot method returning input values. ...@@ -234,7 +242,7 @@ Tests DOMSnapshot.getSnapshot method returning input values.
"inputValue": "ButtonValue", "inputValue": "ButtonValue",
"backendNodeId": "<number>", "backendNodeId": "<number>",
"childNodeIndexes": [ "childNodeIndexes": [
19 20
], ],
"attributes": [ "attributes": [
{ {
...@@ -403,7 +411,7 @@ Tests DOMSnapshot.getSnapshot method returning input values. ...@@ -403,7 +411,7 @@ Tests DOMSnapshot.getSnapshot method returning input values.
"textValue": "TextAreaValue", "textValue": "TextAreaValue",
"backendNodeId": "<number>", "backendNodeId": "<number>",
"childNodeIndexes": [ "childNodeIndexes": [
30 31
], ],
"attributes": [ "attributes": [
{ {
...@@ -419,7 +427,7 @@ Tests DOMSnapshot.getSnapshot method returning input values. ...@@ -419,7 +427,7 @@ Tests DOMSnapshot.getSnapshot method returning input values.
"nodeValue": "", "nodeValue": "",
"backendNodeId": "<number>", "backendNodeId": "<number>",
"childNodeIndexes": [ "childNodeIndexes": [
31 32
], ],
"layoutNodeIndex": 22, "layoutNodeIndex": 22,
"shadowRootType": "user-agent", "shadowRootType": "user-agent",
......
...@@ -81,6 +81,7 @@ instead of "initial value". ...@@ -81,6 +81,7 @@ instead of "initial value".
| <shadow:root> | <shadow:root>
| "inserted value" | "inserted value"
| <shadow:root> | <shadow:root>
| <div>
| <slot> | <slot>
| name="user-agent-custom-assign-slot" | name="user-agent-custom-assign-slot"
| "input.value: initial value" | "input.value: initial value"
......
...@@ -90,6 +90,7 @@ instead of "initial value". ...@@ -90,6 +90,7 @@ instead of "initial value".
| <shadow:root> | <shadow:root>
| "inserted value" | "inserted value"
| <shadow:root> | <shadow:root>
| <div>
| <slot> | <slot>
| name="user-agent-custom-assign-slot" | name="user-agent-custom-assign-slot"
| "input.value: initial value" | "input.value: initial value"
......
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