зеркало из https://github.com/mozilla/gecko-dev.git
servo: Merge #10834 - added support for :read-only and :read-write pseudo-classes (from yoava333:master); r=SimonSapin
partial fix for https://github.com/servo/servo/issues/10732 It's not a full fix because: 1. there's a bug in wpt-test https://github.com/w3c/web-platform-tests/issues/2889#issuecomment-214144420 2. we don't fully support all input types (namely image, color, hidden and range), which are defaulted to input text. this means that :read-write which is applicable to input text is mis-handled in those cases. 3. we don't support contenteditable, which is also possibly :read-write Source-Repo: https://github.com/servo/servo Source-Revision: ac8406f4aebe1e8571319a1d56fc627ea5782e60
This commit is contained in:
Родитель
fc7055d9f4
Коммит
45ed58f663
|
@ -550,13 +550,17 @@ impl<'le> ::selectors::Element for ServoLayoutElement<'le> {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
NonTSPseudoClass::ReadOnly =>
|
||||||
|
!self.element.get_state_for_layout().contains(pseudo_class.state_flag()),
|
||||||
|
|
||||||
NonTSPseudoClass::Active |
|
NonTSPseudoClass::Active |
|
||||||
NonTSPseudoClass::Focus |
|
NonTSPseudoClass::Focus |
|
||||||
NonTSPseudoClass::Hover |
|
NonTSPseudoClass::Hover |
|
||||||
NonTSPseudoClass::Enabled |
|
NonTSPseudoClass::Enabled |
|
||||||
NonTSPseudoClass::Disabled |
|
NonTSPseudoClass::Disabled |
|
||||||
NonTSPseudoClass::Checked |
|
NonTSPseudoClass::Checked |
|
||||||
NonTSPseudoClass::Indeterminate =>
|
NonTSPseudoClass::Indeterminate |
|
||||||
|
NonTSPseudoClass::ReadWrite =>
|
||||||
self.element.get_state_for_layout().contains(pseudo_class.state_flag())
|
self.element.get_state_for_layout().contains(pseudo_class.state_flag())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2161,13 +2161,17 @@ impl<'a> ::selectors::Element for Root<Element> {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
NonTSPseudoClass::ReadOnly =>
|
||||||
|
!Element::state(self).contains(pseudo_class.state_flag()),
|
||||||
|
|
||||||
NonTSPseudoClass::Active |
|
NonTSPseudoClass::Active |
|
||||||
NonTSPseudoClass::Focus |
|
NonTSPseudoClass::Focus |
|
||||||
NonTSPseudoClass::Hover |
|
NonTSPseudoClass::Hover |
|
||||||
NonTSPseudoClass::Enabled |
|
NonTSPseudoClass::Enabled |
|
||||||
NonTSPseudoClass::Disabled |
|
NonTSPseudoClass::Disabled |
|
||||||
NonTSPseudoClass::Checked |
|
NonTSPseudoClass::Checked |
|
||||||
NonTSPseudoClass::Indeterminate =>
|
NonTSPseudoClass::Indeterminate |
|
||||||
|
NonTSPseudoClass::ReadWrite =>
|
||||||
Element::state(self).contains(pseudo_class.state_flag()),
|
Element::state(self).contains(pseudo_class.state_flag()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2430,6 +2434,14 @@ impl Element {
|
||||||
pub fn set_disabled_state(&self, value: bool) {
|
pub fn set_disabled_state(&self, value: bool) {
|
||||||
self.set_state(IN_DISABLED_STATE, value)
|
self.set_state(IN_DISABLED_STATE, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn read_write_state(&self) -> bool {
|
||||||
|
self.state.get().contains(IN_READ_WRITE_STATE)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_read_write_state(&self, value: bool) {
|
||||||
|
self.set_state(IN_READ_WRITE_STATE, value)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Element {
|
impl Element {
|
||||||
|
|
|
@ -125,7 +125,7 @@ impl HTMLInputElement {
|
||||||
let chan = document.window().constellation_chan().clone();
|
let chan = document.window().constellation_chan().clone();
|
||||||
HTMLInputElement {
|
HTMLInputElement {
|
||||||
htmlelement:
|
htmlelement:
|
||||||
HTMLElement::new_inherited_with_state(IN_ENABLED_STATE,
|
HTMLElement::new_inherited_with_state(IN_ENABLED_STATE | IN_READ_WRITE_STATE,
|
||||||
localName, prefix, document),
|
localName, prefix, document),
|
||||||
input_type: Cell::new(InputType::InputText),
|
input_type: Cell::new(InputType::InputText),
|
||||||
placeholder: DOMRefCell::new(DOMString::new()),
|
placeholder: DOMRefCell::new(DOMString::new()),
|
||||||
|
@ -713,6 +713,11 @@ impl VirtualMethods for HTMLInputElement {
|
||||||
el.set_disabled_state(disabled_state);
|
el.set_disabled_state(disabled_state);
|
||||||
el.set_enabled_state(!disabled_state);
|
el.set_enabled_state(!disabled_state);
|
||||||
el.check_ancestors_disabled_state_for_form_control();
|
el.check_ancestors_disabled_state_for_form_control();
|
||||||
|
|
||||||
|
if self.input_type.get() == InputType::InputText {
|
||||||
|
let read_write = !(self.ReadOnly() || el.disabled_state());
|
||||||
|
el.set_read_write_state(read_write);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
&atom!("checked") if !self.checked_changed.get() => {
|
&atom!("checked") if !self.checked_changed.get() => {
|
||||||
let checked_state = match mutation {
|
let checked_state = match mutation {
|
||||||
|
@ -748,6 +753,15 @@ impl VirtualMethods for HTMLInputElement {
|
||||||
// https://html.spec.whatwg.org/multipage/#input-type-change
|
// https://html.spec.whatwg.org/multipage/#input-type-change
|
||||||
let (old_value_mode, old_idl_value) = (self.value_mode(), self.Value());
|
let (old_value_mode, old_idl_value) = (self.value_mode(), self.Value());
|
||||||
self.input_type.set(new_type);
|
self.input_type.set(new_type);
|
||||||
|
|
||||||
|
let el = self.upcast::<Element>();
|
||||||
|
if new_type == InputType::InputText {
|
||||||
|
let read_write = !(self.ReadOnly() || el.disabled_state());
|
||||||
|
el.set_read_write_state(read_write);
|
||||||
|
} else {
|
||||||
|
el.set_read_write_state(false);
|
||||||
|
}
|
||||||
|
|
||||||
let new_value_mode = self.value_mode();
|
let new_value_mode = self.value_mode();
|
||||||
|
|
||||||
match (&old_value_mode, old_idl_value.is_empty(), new_value_mode) {
|
match (&old_value_mode, old_idl_value.is_empty(), new_value_mode) {
|
||||||
|
@ -792,6 +806,10 @@ impl VirtualMethods for HTMLInputElement {
|
||||||
self.radio_group_name().as_ref());
|
self.radio_group_name().as_ref());
|
||||||
}
|
}
|
||||||
self.input_type.set(InputType::InputText);
|
self.input_type.set(InputType::InputText);
|
||||||
|
let el = self.upcast::<Element>();
|
||||||
|
|
||||||
|
let read_write = !(self.ReadOnly() || el.disabled_state());
|
||||||
|
el.set_read_write_state(read_write);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -825,6 +843,17 @@ impl VirtualMethods for HTMLInputElement {
|
||||||
attr.value().chars().filter(|&c| c != '\n' && c != '\r'));
|
attr.value().chars().filter(|&c| c != '\n' && c != '\r'));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
&atom!("readonly") if self.input_type.get() == InputType::InputText => {
|
||||||
|
let el = self.upcast::<Element>();
|
||||||
|
match mutation {
|
||||||
|
AttributeMutation::Set(_) => {
|
||||||
|
el.set_read_write_state(false);
|
||||||
|
},
|
||||||
|
AttributeMutation::Removed => {
|
||||||
|
el.set_read_write_state(!el.disabled_state());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => {},
|
_ => {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -103,7 +103,7 @@ impl HTMLTextAreaElement {
|
||||||
let chan = document.window().constellation_chan().clone();
|
let chan = document.window().constellation_chan().clone();
|
||||||
HTMLTextAreaElement {
|
HTMLTextAreaElement {
|
||||||
htmlelement:
|
htmlelement:
|
||||||
HTMLElement::new_inherited_with_state(IN_ENABLED_STATE,
|
HTMLElement::new_inherited_with_state(IN_ENABLED_STATE | IN_READ_WRITE_STATE,
|
||||||
localName, prefix, document),
|
localName, prefix, document),
|
||||||
textinput: DOMRefCell::new(TextInput::new(
|
textinput: DOMRefCell::new(TextInput::new(
|
||||||
Lines::Multiple, DOMString::new(), chan, None, SelectionDirection::None)),
|
Lines::Multiple, DOMString::new(), chan, None, SelectionDirection::None)),
|
||||||
|
@ -289,14 +289,31 @@ impl VirtualMethods for HTMLTextAreaElement {
|
||||||
AttributeMutation::Set(_) => {
|
AttributeMutation::Set(_) => {
|
||||||
el.set_disabled_state(true);
|
el.set_disabled_state(true);
|
||||||
el.set_enabled_state(false);
|
el.set_enabled_state(false);
|
||||||
|
|
||||||
|
el.set_read_write_state(false);
|
||||||
},
|
},
|
||||||
AttributeMutation::Removed => {
|
AttributeMutation::Removed => {
|
||||||
el.set_disabled_state(false);
|
el.set_disabled_state(false);
|
||||||
el.set_enabled_state(true);
|
el.set_enabled_state(true);
|
||||||
el.check_ancestors_disabled_state_for_form_control();
|
el.check_ancestors_disabled_state_for_form_control();
|
||||||
|
|
||||||
|
if !el.disabled_state() && !el.read_write_state() {
|
||||||
|
el.set_read_write_state(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
atom!("readonly") => {
|
||||||
|
let el = self.upcast::<Element>();
|
||||||
|
match mutation {
|
||||||
|
AttributeMutation::Set(_) => {
|
||||||
|
el.set_read_write_state(false);
|
||||||
|
},
|
||||||
|
AttributeMutation::Removed => {
|
||||||
|
el.set_read_write_state(!el.disabled_state());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => {},
|
_ => {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,5 +27,7 @@ bitflags! {
|
||||||
const IN_CHECKED_STATE = 0x20,
|
const IN_CHECKED_STATE = 0x20,
|
||||||
#[doc = "https://html.spec.whatwg.org/multipage/#selector-indeterminate"]
|
#[doc = "https://html.spec.whatwg.org/multipage/#selector-indeterminate"]
|
||||||
const IN_INDETERMINATE_STATE = 0x40,
|
const IN_INDETERMINATE_STATE = 0x40,
|
||||||
|
#[doc = "https://html.spec.whatwg.org/multipage/#selector-read-write"]
|
||||||
|
const IN_READ_WRITE_STATE = 0x80,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,6 +44,8 @@ pub enum NonTSPseudoClass {
|
||||||
Checked,
|
Checked,
|
||||||
Indeterminate,
|
Indeterminate,
|
||||||
ServoNonZeroBorder,
|
ServoNonZeroBorder,
|
||||||
|
ReadWrite,
|
||||||
|
ReadOnly
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NonTSPseudoClass {
|
impl NonTSPseudoClass {
|
||||||
|
@ -58,6 +60,7 @@ impl NonTSPseudoClass {
|
||||||
Disabled => IN_DISABLED_STATE,
|
Disabled => IN_DISABLED_STATE,
|
||||||
Checked => IN_CHECKED_STATE,
|
Checked => IN_CHECKED_STATE,
|
||||||
Indeterminate => IN_INDETERMINATE_STATE,
|
Indeterminate => IN_INDETERMINATE_STATE,
|
||||||
|
ReadOnly | ReadWrite => IN_READ_WRITE_STATE,
|
||||||
|
|
||||||
AnyLink |
|
AnyLink |
|
||||||
Link |
|
Link |
|
||||||
|
@ -88,6 +91,8 @@ impl SelectorImpl for ServoSelectorImpl {
|
||||||
"disabled" => Disabled,
|
"disabled" => Disabled,
|
||||||
"checked" => Checked,
|
"checked" => Checked,
|
||||||
"indeterminate" => Indeterminate,
|
"indeterminate" => Indeterminate,
|
||||||
|
"read-write" => ReadWrite,
|
||||||
|
"read-only" => ReadOnly,
|
||||||
"-servo-nonzero-border" => {
|
"-servo-nonzero-border" => {
|
||||||
if !context.in_user_agent_stylesheet {
|
if !context.in_user_agent_stylesheet {
|
||||||
return Err(());
|
return Err(());
|
||||||
|
|
|
@ -101,6 +101,8 @@ pub enum NonTSPseudoClass {
|
||||||
Disabled,
|
Disabled,
|
||||||
Checked,
|
Checked,
|
||||||
Indeterminate,
|
Indeterminate,
|
||||||
|
ReadWrite,
|
||||||
|
ReadOnly,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NonTSPseudoClass {
|
impl NonTSPseudoClass {
|
||||||
|
@ -115,6 +117,7 @@ impl NonTSPseudoClass {
|
||||||
Disabled => IN_DISABLED_STATE,
|
Disabled => IN_DISABLED_STATE,
|
||||||
Checked => IN_CHECKED_STATE,
|
Checked => IN_CHECKED_STATE,
|
||||||
Indeterminate => IN_INDETERMINATE_STATE,
|
Indeterminate => IN_INDETERMINATE_STATE,
|
||||||
|
ReadOnly | ReadWrite => IN_READ_WRITE_STATE,
|
||||||
|
|
||||||
AnyLink |
|
AnyLink |
|
||||||
Link |
|
Link |
|
||||||
|
@ -140,6 +143,8 @@ impl SelectorImpl for GeckoSelectorImpl {
|
||||||
"disabled" => Disabled,
|
"disabled" => Disabled,
|
||||||
"checked" => Checked,
|
"checked" => Checked,
|
||||||
"indeterminate" => Indeterminate,
|
"indeterminate" => Indeterminate,
|
||||||
|
"read-write" => ReadWrite,
|
||||||
|
"read-only" => ReadOnly,
|
||||||
_ => return Err(())
|
_ => return Err(())
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -437,9 +437,13 @@ impl<'le> ::selectors::Element for GeckoElement<'le> {
|
||||||
NonTSPseudoClass::Enabled |
|
NonTSPseudoClass::Enabled |
|
||||||
NonTSPseudoClass::Disabled |
|
NonTSPseudoClass::Disabled |
|
||||||
NonTSPseudoClass::Checked |
|
NonTSPseudoClass::Checked |
|
||||||
|
NonTSPseudoClass::ReadWrite |
|
||||||
NonTSPseudoClass::Indeterminate => {
|
NonTSPseudoClass::Indeterminate => {
|
||||||
self.get_state().contains(pseudo_class.state_flag())
|
self.get_state().contains(pseudo_class.state_flag())
|
||||||
},
|
},
|
||||||
|
NonTSPseudoClass::ReadOnly => {
|
||||||
|
!self.get_state().contains(pseudo_class.state_flag())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче