Skip to content

Commit

Permalink
added support for :read-only and :read-write pseudo-classes
Browse files Browse the repository at this point in the history
partial fix for #10732
  • Loading branch information
yoava333 committed Apr 26, 2016
1 parent f773dc1 commit 9bf909a
Show file tree
Hide file tree
Showing 9 changed files with 82 additions and 31 deletions.
6 changes: 5 additions & 1 deletion components/layout/wrapper.rs
Expand Up @@ -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::Focus |
NonTSPseudoClass::Hover |
NonTSPseudoClass::Enabled |
NonTSPseudoClass::Disabled |
NonTSPseudoClass::Checked |
NonTSPseudoClass::Indeterminate =>
NonTSPseudoClass::Indeterminate |
NonTSPseudoClass::ReadWrite =>
self.element.get_state_for_layout().contains(pseudo_class.state_flag())
}
}
Expand Down
14 changes: 13 additions & 1 deletion components/script/dom/element.rs
Expand Up @@ -2161,13 +2161,17 @@ impl<'a> ::selectors::Element for Root<Element> {
}
},

NonTSPseudoClass::ReadOnly =>
!Element::state(self).contains(pseudo_class.state_flag()),

NonTSPseudoClass::Active |
NonTSPseudoClass::Focus |
NonTSPseudoClass::Hover |
NonTSPseudoClass::Enabled |
NonTSPseudoClass::Disabled |
NonTSPseudoClass::Checked |
NonTSPseudoClass::Indeterminate =>
NonTSPseudoClass::Indeterminate |
NonTSPseudoClass::ReadWrite =>
Element::state(self).contains(pseudo_class.state_flag()),
}
}
Expand Down Expand Up @@ -2430,6 +2434,14 @@ impl Element {
pub fn set_disabled_state(&self, value: bool) {
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 {
Expand Down
31 changes: 30 additions & 1 deletion components/script/dom/htmlinputelement.rs
Expand Up @@ -124,7 +124,7 @@ impl HTMLInputElement {
let chan = document.window().constellation_chan();
HTMLInputElement {
htmlelement:
HTMLElement::new_inherited_with_state(IN_ENABLED_STATE,
HTMLElement::new_inherited_with_state(IN_ENABLED_STATE | IN_READ_WRITE_STATE,
localName, prefix, document),
input_type: Cell::new(InputType::InputText),
placeholder: DOMRefCell::new(DOMString::new()),
Expand Down Expand Up @@ -710,6 +710,11 @@ impl VirtualMethods for HTMLInputElement {
el.set_disabled_state(disabled_state);
el.set_enabled_state(!disabled_state);
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() => {
let checked_state = match mutation {
Expand Down Expand Up @@ -745,6 +750,15 @@ impl VirtualMethods for HTMLInputElement {
// https://html.spec.whatwg.org/multipage/#input-type-change
let (old_value_mode, old_idl_value) = (self.value_mode(), self.Value());
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();

match (&old_value_mode, old_idl_value.is_empty(), new_value_mode) {
Expand Down Expand Up @@ -789,6 +803,10 @@ impl VirtualMethods for HTMLInputElement {
self.radio_group_name().as_ref());
}
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);
}
}
},
Expand Down Expand Up @@ -822,6 +840,17 @@ impl VirtualMethods for HTMLInputElement {
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());
}
}
}
_ => {},
}
}
Expand Down
19 changes: 18 additions & 1 deletion components/script/dom/htmltextareaelement.rs
Expand Up @@ -104,7 +104,7 @@ impl HTMLTextAreaElement {
let chan = document.window().constellation_chan();
HTMLTextAreaElement {
htmlelement:
HTMLElement::new_inherited_with_state(IN_ENABLED_STATE,
HTMLElement::new_inherited_with_state(IN_ENABLED_STATE | IN_READ_WRITE_STATE,
localName, prefix, document),
textinput: DOMRefCell::new(TextInput::new(
Lines::Multiple, DOMString::new(), chan, None, SelectionDirection::None)),
Expand Down Expand Up @@ -290,14 +290,31 @@ impl VirtualMethods for HTMLTextAreaElement {
AttributeMutation::Set(_) => {
el.set_disabled_state(true);
el.set_enabled_state(false);

el.set_read_write_state(false);
},
AttributeMutation::Removed => {
el.set_disabled_state(false);
el.set_enabled_state(true);
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());
}
}
}
_ => {},
}
}
Expand Down
2 changes: 2 additions & 0 deletions components/style/element_state.rs
Expand Up @@ -27,5 +27,7 @@ bitflags! {
const IN_CHECKED_STATE = 0x20,
#[doc = "https://html.spec.whatwg.org/multipage/#selector-indeterminate"]
const IN_INDETERMINATE_STATE = 0x40,
#[doc = "https://html.spec.whatwg.org/multipage/#selector-read-write"]
const IN_READ_WRITE_STATE = 0x80,
}
}
5 changes: 5 additions & 0 deletions components/style/selector_impl.rs
Expand Up @@ -44,6 +44,8 @@ pub enum NonTSPseudoClass {
Checked,
Indeterminate,
ServoNonZeroBorder,
ReadWrite,
ReadOnly
}

impl NonTSPseudoClass {
Expand All @@ -58,6 +60,7 @@ impl NonTSPseudoClass {
Disabled => IN_DISABLED_STATE,
Checked => IN_CHECKED_STATE,
Indeterminate => IN_INDETERMINATE_STATE,
ReadOnly | ReadWrite => IN_READ_WRITE_STATE,

AnyLink |
Link |
Expand Down Expand Up @@ -88,6 +91,8 @@ impl SelectorImpl for ServoSelectorImpl {
"disabled" => Disabled,
"checked" => Checked,
"indeterminate" => Indeterminate,
"read-write" => ReadWrite,
"read-only" => ReadOnly,
"-servo-nonzero-border" => {
if !context.in_user_agent_stylesheet {
return Err(());
Expand Down
5 changes: 5 additions & 0 deletions ports/geckolib/selector_impl.rs
Expand Up @@ -101,6 +101,8 @@ pub enum NonTSPseudoClass {
Disabled,
Checked,
Indeterminate,
ReadWrite,
ReadOnly,
}

impl NonTSPseudoClass {
Expand All @@ -115,6 +117,7 @@ impl NonTSPseudoClass {
Disabled => IN_DISABLED_STATE,
Checked => IN_CHECKED_STATE,
Indeterminate => IN_INDETERMINATE_STATE,
ReadOnly | ReadWrite => IN_READ_WRITE_STATE,

AnyLink |
Link |
Expand All @@ -140,6 +143,8 @@ impl SelectorImpl for GeckoSelectorImpl {
"disabled" => Disabled,
"checked" => Checked,
"indeterminate" => Indeterminate,
"read-write" => ReadWrite,
"read-only" => ReadOnly,
_ => return Err(())
};

Expand Down
4 changes: 4 additions & 0 deletions ports/geckolib/wrapper.rs
Expand Up @@ -437,9 +437,13 @@ impl<'le> ::selectors::Element for GeckoElement<'le> {
NonTSPseudoClass::Enabled |
NonTSPseudoClass::Disabled |
NonTSPseudoClass::Checked |
NonTSPseudoClass::ReadWrite |
NonTSPseudoClass::Indeterminate => {
self.get_state().contains(pseudo_class.state_flag())
},
NonTSPseudoClass::ReadOnly => {
!self.get_state().contains(pseudo_class.state_flag())
}
}
}

Expand Down
@@ -1,42 +1,15 @@
[readwrite-readonly.html]
type: testharness
bug: https://github.com/servo/servo/issues/10732
[The :read-write pseudo-class must match input elements to which the readonly attribute applies, and that are mutable]
expected: FAIL

[The :read-only pseudo-class must not match input elements to which the readonly attribute applies, and that are mutable]
expected: FAIL

[The :read-write pseudo-class must not match input elements after the readonly attribute has been added]
expected: FAIL

[The :read-only pseudo-class must match input elements after the readonly attribute has been added]
expected: FAIL

[The :read-write pseudo-class must not match input elements after the readonly attribute has been removed]
expected: FAIL

[The :read-only pseudo-class must match input elements after the readonly attribute has been removed]
expected: FAIL

[The :read-write pseudo-class must match textarea elements that do not have a readonly attribute, and that are not disabled]
expected: FAIL

[The :read-only pseudo-class must match textarea elements that have a readonly attribute, or that are disabled]
expected: FAIL

[The :read-write pseudo-class must match textarea elements after the readonly attribute has been added]
expected: FAIL

[The :read-only pseudo-class must match textarea elements after the readonly attribute has been added]
expected: FAIL

[The :read-write pseudo-class must not match textarea elements that are disabled]
expected: FAIL

[The :read-only pseudo-class must match textarea elements that are disabled]
expected: FAIL

[The :read-write pseudo-class must match elements that are editable]
expected: FAIL

Expand Down

0 comments on commit 9bf909a

Please sign in to comment.