mirror of
https://github.com/servo/servo.git
synced 2025-08-05 05:30:08 +01:00
This reverts commit 5580704438
.
Let's re-land that fix when a working solution is found. Keeping that
regression makes it hard to evaluate other potential improvements.
Signed-off-by: webbeef <me@webbeef.org>
This commit is contained in:
parent
aff2a85372
commit
a1f43ab06d
24 changed files with 36 additions and 635 deletions
|
@ -59,14 +59,8 @@ impl<'dom> NodeAndStyleInfo<'dom> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Whether this is a container for the editable text within a single-line text input.
|
|
||||||
/// This is used to solve the special case of line height for a text editor.
|
|
||||||
/// <https://html.spec.whatwg.org/multipage/#the-input-element-as-a-text-entry-widget>
|
|
||||||
// FIXME(stevennovaryo): Now, this would also refer to HTMLInputElement, to handle input
|
|
||||||
// elements without shadow DOM.
|
|
||||||
pub(crate) fn is_single_line_text_input(&self) -> bool {
|
pub(crate) fn is_single_line_text_input(&self) -> bool {
|
||||||
self.node.type_id() == LayoutNodeType::Element(LayoutElementType::HTMLInputElement) ||
|
self.node.type_id() == LayoutNodeType::Element(LayoutElementType::HTMLInputElement)
|
||||||
self.node.is_text_control_inner_editor()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn pseudo(
|
pub(crate) fn pseudo(
|
||||||
|
|
|
@ -1556,14 +1556,11 @@ impl Document {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// For a node within a text input UA shadow DOM, delegate the focus target into its shadow host.
|
|
||||||
// TODO: This focus delegation should be done with shadow DOM delegateFocus attribute.
|
|
||||||
let target_el = el.find_focusable_shadow_host_if_necessary();
|
|
||||||
|
|
||||||
self.begin_focus_transaction();
|
self.begin_focus_transaction();
|
||||||
// Try to focus `el`. If it's not focusable, focus the document instead.
|
// Try to focus `el`. If it's not focusable, focus the document
|
||||||
|
// instead.
|
||||||
self.request_focus(None, FocusInitiator::Local, can_gc);
|
self.request_focus(None, FocusInitiator::Local, can_gc);
|
||||||
self.request_focus(target_el.as_deref(), FocusInitiator::Local, can_gc);
|
self.request_focus(Some(&*el), FocusInitiator::Local, can_gc);
|
||||||
}
|
}
|
||||||
|
|
||||||
let dom_event = DomRoot::upcast::<Event>(MouseEvent::for_platform_mouse_event(
|
let dom_event = DomRoot::upcast::<Event>(MouseEvent::for_platform_mouse_event(
|
||||||
|
|
|
@ -1703,27 +1703,6 @@ impl Element {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the focusable shadow host if this is a text control inner editor.
|
|
||||||
/// This is a workaround for the focus delegation of shadow DOM and should be
|
|
||||||
/// used only to delegate focusable inner editor of [HTMLInputElement] and
|
|
||||||
/// [HTMLTextAreaElement].
|
|
||||||
pub(crate) fn find_focusable_shadow_host_if_necessary(&self) -> Option<DomRoot<Element>> {
|
|
||||||
if self.is_focusable_area() {
|
|
||||||
Some(DomRoot::from_ref(self))
|
|
||||||
} else if self.upcast::<Node>().is_text_control_inner_editor() {
|
|
||||||
let containing_shadow_host = self.containing_shadow_root().map(|root| root.Host());
|
|
||||||
assert!(
|
|
||||||
containing_shadow_host
|
|
||||||
.as_ref()
|
|
||||||
.is_some_and(|e| e.is_focusable_area()),
|
|
||||||
"Containing shadow host is not focusable"
|
|
||||||
);
|
|
||||||
containing_shadow_host
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn is_actually_disabled(&self) -> bool {
|
pub(crate) fn is_actually_disabled(&self) -> bool {
|
||||||
let node = self.upcast::<Node>();
|
let node = self.upcast::<Node>();
|
||||||
match node.type_id() {
|
match node.type_id() {
|
||||||
|
|
|
@ -101,29 +101,6 @@ const DEFAULT_RESET_VALUE: &str = "Reset";
|
||||||
const PASSWORD_REPLACEMENT_CHAR: char = '●';
|
const PASSWORD_REPLACEMENT_CHAR: char = '●';
|
||||||
const DEFAULT_FILE_INPUT_VALUE: &str = "No file chosen";
|
const DEFAULT_FILE_INPUT_VALUE: &str = "No file chosen";
|
||||||
|
|
||||||
#[derive(Clone, JSTraceable, MallocSizeOf)]
|
|
||||||
#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
|
|
||||||
/// Contains reference to text control inner editor and placeholder container element in the UA
|
|
||||||
/// shadow tree for `<input type=text>`. The following is the structure of the shadow tree.
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// <input type="text">
|
|
||||||
/// #shadow-root
|
|
||||||
/// <div id="inner-container">
|
|
||||||
/// <div id="input-editor"></div>
|
|
||||||
/// <div id="input-placeholder"></div>
|
|
||||||
/// </div>
|
|
||||||
/// </input>
|
|
||||||
/// ```
|
|
||||||
// TODO(stevennovaryo): We are trying to use CSS to mimic Chrome and Firefox's layout for the <input> element.
|
|
||||||
// But, this could be slower in performance and does have some discrepancies. For example,
|
|
||||||
// they would try to vertically align <input> text baseline with the baseline of other
|
|
||||||
// TextNode within an inline flow. Another example is the horizontal scroll.
|
|
||||||
struct InputTypeTextShadowTree {
|
|
||||||
text_container: Dom<HTMLDivElement>,
|
|
||||||
placeholder_container: Dom<HTMLDivElement>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, JSTraceable, MallocSizeOf)]
|
#[derive(Clone, JSTraceable, MallocSizeOf)]
|
||||||
#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
|
#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
|
||||||
/// Contains references to the elements in the shadow tree for `<input type=range>`.
|
/// Contains references to the elements in the shadow tree for `<input type=range>`.
|
||||||
|
@ -134,49 +111,10 @@ struct InputTypeColorShadowTree {
|
||||||
color_value: Dom<HTMLDivElement>,
|
color_value: Dom<HTMLDivElement>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: These styles should be inside UA stylesheet, but it is not possible without internal pseudo element support.
|
|
||||||
const TEXT_TREE_STYLE: &str = "
|
|
||||||
#input-editor::selection {
|
|
||||||
background: rgba(176, 214, 255, 1.0);
|
|
||||||
color: black;
|
|
||||||
}
|
|
||||||
|
|
||||||
:host:not(:placeholder-shown) #input-placeholder {
|
|
||||||
visibility: hidden !important
|
|
||||||
}
|
|
||||||
|
|
||||||
#input-editor {
|
|
||||||
overflow-wrap: normal;
|
|
||||||
pointer-events: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
#input-container {
|
|
||||||
position: relative;
|
|
||||||
height: 100%;
|
|
||||||
pointer-events: none;
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
|
|
||||||
#input-editor, #input-placeholder {
|
|
||||||
white-space: pre;
|
|
||||||
margin-block: auto !important;
|
|
||||||
inset-block: 0 !important;
|
|
||||||
block-size: fit-content !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
#input-placeholder {
|
|
||||||
overflow: hidden !important;
|
|
||||||
position: absolute !important;
|
|
||||||
color: grey;
|
|
||||||
pointer-events: none !important;
|
|
||||||
}
|
|
||||||
";
|
|
||||||
|
|
||||||
#[derive(Clone, JSTraceable, MallocSizeOf)]
|
#[derive(Clone, JSTraceable, MallocSizeOf)]
|
||||||
#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
|
#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
enum ShadowTree {
|
enum ShadowTree {
|
||||||
Text(InputTypeTextShadowTree),
|
|
||||||
Color(InputTypeColorShadowTree),
|
Color(InputTypeColorShadowTree),
|
||||||
// TODO: Add shadow trees for other input types (range etc) here
|
// TODO: Add shadow trees for other input types (range etc) here
|
||||||
}
|
}
|
||||||
|
@ -1133,7 +1071,7 @@ impl HTMLInputElement {
|
||||||
ShadowRootMode::Closed,
|
ShadowRootMode::Closed,
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
true,
|
false,
|
||||||
SlotAssignmentMode::Manual,
|
SlotAssignmentMode::Manual,
|
||||||
can_gc,
|
can_gc,
|
||||||
)
|
)
|
||||||
|
@ -1141,92 +1079,6 @@ impl HTMLInputElement {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_text_shadow_tree(&self, can_gc: CanGc) {
|
|
||||||
let document = self.owner_document();
|
|
||||||
let shadow_root = self.shadow_root(can_gc);
|
|
||||||
Node::replace_all(None, shadow_root.upcast::<Node>(), can_gc);
|
|
||||||
|
|
||||||
let inner_container =
|
|
||||||
HTMLDivElement::new(local_name!("div"), None, &document, None, can_gc);
|
|
||||||
inner_container
|
|
||||||
.upcast::<Element>()
|
|
||||||
.SetId(DOMString::from("input-container"), can_gc);
|
|
||||||
shadow_root
|
|
||||||
.upcast::<Node>()
|
|
||||||
.AppendChild(inner_container.upcast::<Node>(), can_gc)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let placeholder_container =
|
|
||||||
HTMLDivElement::new(local_name!("div"), None, &document, None, can_gc);
|
|
||||||
placeholder_container
|
|
||||||
.upcast::<Element>()
|
|
||||||
.SetId(DOMString::from("input-placeholder"), can_gc);
|
|
||||||
inner_container
|
|
||||||
.upcast::<Node>()
|
|
||||||
.AppendChild(placeholder_container.upcast::<Node>(), can_gc)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let text_container = HTMLDivElement::new(local_name!("div"), None, &document, None, can_gc);
|
|
||||||
text_container
|
|
||||||
.upcast::<Element>()
|
|
||||||
.SetId(DOMString::from("input-editor"), can_gc);
|
|
||||||
text_container
|
|
||||||
.upcast::<Node>()
|
|
||||||
.set_text_control_inner_editor();
|
|
||||||
inner_container
|
|
||||||
.upcast::<Node>()
|
|
||||||
.AppendChild(text_container.upcast::<Node>(), can_gc)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let style = HTMLStyleElement::new(
|
|
||||||
local_name!("style"),
|
|
||||||
None,
|
|
||||||
&document,
|
|
||||||
None,
|
|
||||||
ElementCreator::ScriptCreated,
|
|
||||||
can_gc,
|
|
||||||
);
|
|
||||||
// TODO(stevennovaryo): Either use UA stylesheet with internal pseudo element or preemptively parse
|
|
||||||
// the stylesheet to reduce the costly operation and avoid CSP related error.
|
|
||||||
style
|
|
||||||
.upcast::<Node>()
|
|
||||||
.SetTextContent(Some(DOMString::from(TEXT_TREE_STYLE)), can_gc);
|
|
||||||
shadow_root
|
|
||||||
.upcast::<Node>()
|
|
||||||
.AppendChild(style.upcast::<Node>(), can_gc)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let _ = self
|
|
||||||
.shadow_tree
|
|
||||||
.borrow_mut()
|
|
||||||
.insert(ShadowTree::Text(InputTypeTextShadowTree {
|
|
||||||
text_container: text_container.as_traced(),
|
|
||||||
placeholder_container: placeholder_container.as_traced(),
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn text_shadow_tree(&self, can_gc: CanGc) -> Ref<InputTypeTextShadowTree> {
|
|
||||||
let has_text_shadow_tree = self
|
|
||||||
.shadow_tree
|
|
||||||
.borrow()
|
|
||||||
.as_ref()
|
|
||||||
.is_some_and(|shadow_tree| matches!(shadow_tree, ShadowTree::Text(_)));
|
|
||||||
if !has_text_shadow_tree {
|
|
||||||
self.create_text_shadow_tree(can_gc);
|
|
||||||
}
|
|
||||||
|
|
||||||
let shadow_tree = self.shadow_tree.borrow();
|
|
||||||
Ref::filter_map(shadow_tree, |shadow_tree| {
|
|
||||||
let shadow_tree = shadow_tree.as_ref()?;
|
|
||||||
match shadow_tree {
|
|
||||||
ShadowTree::Text(text_tree) => Some(text_tree),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.ok()
|
|
||||||
.expect("UA shadow tree was not created")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn create_color_shadow_tree(&self, can_gc: CanGc) {
|
fn create_color_shadow_tree(&self, can_gc: CanGc) {
|
||||||
let document = self.owner_document();
|
let document = self.owner_document();
|
||||||
let shadow_root = self.shadow_root(can_gc);
|
let shadow_root = self.shadow_root(can_gc);
|
||||||
|
@ -1284,53 +1136,27 @@ impl HTMLInputElement {
|
||||||
let shadow_tree = self.shadow_tree.borrow();
|
let shadow_tree = self.shadow_tree.borrow();
|
||||||
Ref::filter_map(shadow_tree, |shadow_tree| {
|
Ref::filter_map(shadow_tree, |shadow_tree| {
|
||||||
let shadow_tree = shadow_tree.as_ref()?;
|
let shadow_tree = shadow_tree.as_ref()?;
|
||||||
match shadow_tree {
|
let ShadowTree::Color(color_tree) = shadow_tree;
|
||||||
ShadowTree::Color(color_tree) => Some(color_tree),
|
Some(color_tree)
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
.ok()
|
.ok()
|
||||||
.expect("UA shadow tree was not created")
|
.expect("UA shadow tree was not created")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_shadow_tree_if_needed(&self, can_gc: CanGc) {
|
fn update_shadow_tree_if_needed(&self, can_gc: CanGc) {
|
||||||
match self.input_type() {
|
if self.input_type() == InputType::Color {
|
||||||
InputType::Text => {
|
let color_shadow_tree = self.color_shadow_tree(can_gc);
|
||||||
let text_shadow_tree = self.text_shadow_tree(can_gc);
|
let mut value = self.Value();
|
||||||
let value = self.Value();
|
if value.str().is_valid_simple_color_string() {
|
||||||
|
value.make_ascii_lowercase();
|
||||||
// The addition of zero-width space here forces the text input to have an inline formatting
|
} else {
|
||||||
// context that might otherwise be trimmed if there's no text. This is important to ensure
|
value = DOMString::from("#000000");
|
||||||
// that the input element is at least as tall as the line gap of the caret:
|
}
|
||||||
// <https://drafts.csswg.org/css-ui/#element-with-default-preferred-size>.
|
let style = format!("background-color: {value}");
|
||||||
//
|
color_shadow_tree
|
||||||
// This is also used to ensure that the caret will still be rendered when the input is empty.
|
.color_value
|
||||||
// TODO: Is there a less hacky way to do this?
|
.upcast::<Element>()
|
||||||
let value_text = match value.is_empty() {
|
.set_string_attribute(&local_name!("style"), style.into(), can_gc);
|
||||||
false => value,
|
|
||||||
true => "\u{200B}".into(),
|
|
||||||
};
|
|
||||||
|
|
||||||
text_shadow_tree
|
|
||||||
.text_container
|
|
||||||
.upcast::<Node>()
|
|
||||||
.SetTextContent(Some(value_text), can_gc);
|
|
||||||
},
|
|
||||||
InputType::Color => {
|
|
||||||
let color_shadow_tree = self.color_shadow_tree(can_gc);
|
|
||||||
let mut value = self.Value();
|
|
||||||
if value.str().is_valid_simple_color_string() {
|
|
||||||
value.make_ascii_lowercase();
|
|
||||||
} else {
|
|
||||||
value = DOMString::from("#000000");
|
|
||||||
}
|
|
||||||
let style = format!("background-color: {value}");
|
|
||||||
color_shadow_tree
|
|
||||||
.color_value
|
|
||||||
.upcast::<Element>()
|
|
||||||
.set_string_attribute(&local_name!("style"), style.into(), can_gc);
|
|
||||||
},
|
|
||||||
_ => {},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1639,29 +1465,22 @@ impl HTMLInputElementMethods<crate::DomTypeHolder> for HTMLInputElement {
|
||||||
fn SetValue(&self, mut value: DOMString, can_gc: CanGc) -> ErrorResult {
|
fn SetValue(&self, mut value: DOMString, can_gc: CanGc) -> ErrorResult {
|
||||||
match self.value_mode() {
|
match self.value_mode() {
|
||||||
ValueMode::Value => {
|
ValueMode::Value => {
|
||||||
{
|
// Step 3.
|
||||||
// Step 3.
|
self.value_dirty.set(true);
|
||||||
self.value_dirty.set(true);
|
|
||||||
|
|
||||||
// Step 4.
|
// Step 4.
|
||||||
self.sanitize_value(&mut value);
|
self.sanitize_value(&mut value);
|
||||||
|
|
||||||
let mut textinput = self.textinput.borrow_mut();
|
let mut textinput = self.textinput.borrow_mut();
|
||||||
|
|
||||||
|
// Step 5.
|
||||||
|
if *textinput.single_line_content() != value {
|
||||||
|
// Steps 1-2
|
||||||
|
textinput.set_content(value);
|
||||||
|
|
||||||
// Step 5.
|
// Step 5.
|
||||||
if *textinput.single_line_content() != value {
|
textinput.clear_selection_to_limit(Direction::Forward);
|
||||||
// Steps 1-2
|
|
||||||
textinput.set_content(value);
|
|
||||||
|
|
||||||
// Step 5.
|
|
||||||
textinput.clear_selection_to_limit(Direction::Forward);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Additionaly, update the placeholder shown state. This is
|
|
||||||
// normally being done in the attributed mutated. And, being
|
|
||||||
// done in another scope to prevent borrow checker issues.
|
|
||||||
self.update_placeholder_shown_state();
|
|
||||||
},
|
},
|
||||||
ValueMode::Default | ValueMode::DefaultOn => {
|
ValueMode::Default | ValueMode::DefaultOn => {
|
||||||
self.upcast::<Element>()
|
self.upcast::<Element>()
|
||||||
|
@ -2244,19 +2063,6 @@ impl HTMLInputElement {
|
||||||
el.set_placeholder_shown_state(has_placeholder && !has_value);
|
el.set_placeholder_shown_state(has_placeholder && !has_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the placeholder text in the text shadow tree.
|
|
||||||
// To increase the performance, we would only do this when it is necessary.
|
|
||||||
fn update_text_shadow_tree_placeholder(&self, can_gc: CanGc) {
|
|
||||||
if self.input_type() != InputType::Text {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.text_shadow_tree(can_gc)
|
|
||||||
.placeholder_container
|
|
||||||
.upcast::<Node>()
|
|
||||||
.SetTextContent(Some(self.placeholder.borrow().clone()), can_gc);
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/#file-upload-state-(type=file)
|
// https://html.spec.whatwg.org/multipage/#file-upload-state-(type=file)
|
||||||
// Select files by invoking UI or by passed in argument
|
// Select files by invoking UI or by passed in argument
|
||||||
fn select_files(&self, opt_test_paths: Option<Vec<DOMString>>, can_gc: CanGc) {
|
fn select_files(&self, opt_test_paths: Option<Vec<DOMString>>, can_gc: CanGc) {
|
||||||
|
@ -2882,11 +2688,8 @@ impl VirtualMethods for HTMLInputElement {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
self.update_text_shadow_tree_placeholder(can_gc);
|
|
||||||
self.update_placeholder_shown_state();
|
self.update_placeholder_shown_state();
|
||||||
},
|
},
|
||||||
// FIXME(stevennovaryo): This is only reachable by Default and DefaultOn value mode. While others
|
|
||||||
// are being handled in [Self::SetValue]. Should we merge this two together?
|
|
||||||
local_name!("value") if !self.value_dirty.get() => {
|
local_name!("value") if !self.value_dirty.get() => {
|
||||||
let value = mutation.new_value(attr).map(|value| (**value).to_owned());
|
let value = mutation.new_value(attr).map(|value| (**value).to_owned());
|
||||||
let mut value = value.map_or(DOMString::new(), DOMString::from);
|
let mut value = value.map_or(DOMString::new(), DOMString::from);
|
||||||
|
@ -2935,7 +2738,6 @@ impl VirtualMethods for HTMLInputElement {
|
||||||
.extend(attr.value().chars().filter(|&c| c != '\n' && c != '\r'));
|
.extend(attr.value().chars().filter(|&c| c != '\n' && c != '\r'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.update_text_shadow_tree_placeholder(can_gc);
|
|
||||||
self.update_placeholder_shown_state();
|
self.update_placeholder_shown_state();
|
||||||
},
|
},
|
||||||
local_name!("readonly") => {
|
local_name!("readonly") => {
|
||||||
|
|
|
@ -230,10 +230,6 @@ bitflags! {
|
||||||
/// Whether this node has a weird parser insertion mode. i.e whether setting innerHTML
|
/// Whether this node has a weird parser insertion mode. i.e whether setting innerHTML
|
||||||
/// needs extra work or not
|
/// needs extra work or not
|
||||||
const HAS_WEIRD_PARSER_INSERTION_MODE = 1 << 11;
|
const HAS_WEIRD_PARSER_INSERTION_MODE = 1 << 11;
|
||||||
|
|
||||||
/// Whether this node serves as the text container for editable content of
|
|
||||||
/// <input> or <textarea> element.
|
|
||||||
const IS_TEXT_CONTROL_INNER_EDITOR = 1 << 12;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -701,16 +697,6 @@ impl Node {
|
||||||
self.flags.get().contains(NodeFlags::IS_CONNECTED)
|
self.flags.get().contains(NodeFlags::IS_CONNECTED)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn set_text_control_inner_editor(&self) {
|
|
||||||
self.set_flag(NodeFlags::IS_TEXT_CONTROL_INNER_EDITOR, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn is_text_control_inner_editor(&self) -> bool {
|
|
||||||
self.flags
|
|
||||||
.get()
|
|
||||||
.contains(NodeFlags::IS_TEXT_CONTROL_INNER_EDITOR)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the type ID of this node.
|
/// Returns the type ID of this node.
|
||||||
pub(crate) fn type_id(&self) -> NodeTypeId {
|
pub(crate) fn type_id(&self) -> NodeTypeId {
|
||||||
match *self.eventtarget.type_id() {
|
match *self.eventtarget.type_id() {
|
||||||
|
@ -1608,7 +1594,6 @@ pub(crate) trait LayoutNodeHelpers<'dom> {
|
||||||
fn assigned_slot_for_layout(self) -> Option<LayoutDom<'dom, HTMLSlotElement>>;
|
fn assigned_slot_for_layout(self) -> Option<LayoutDom<'dom, HTMLSlotElement>>;
|
||||||
|
|
||||||
fn is_element_for_layout(&self) -> bool;
|
fn is_element_for_layout(&self) -> bool;
|
||||||
fn is_text_node_for_layout(&self) -> bool;
|
|
||||||
unsafe fn get_flag(self, flag: NodeFlags) -> bool;
|
unsafe fn get_flag(self, flag: NodeFlags) -> bool;
|
||||||
unsafe fn set_flag(self, flag: NodeFlags, value: bool);
|
unsafe fn set_flag(self, flag: NodeFlags, value: bool);
|
||||||
|
|
||||||
|
@ -1644,9 +1629,6 @@ pub(crate) trait LayoutNodeHelpers<'dom> {
|
||||||
|
|
||||||
/// Whether this element is a `<input>` rendered as text or a `<textarea>`.
|
/// Whether this element is a `<input>` rendered as text or a `<textarea>`.
|
||||||
fn is_text_input(&self) -> bool;
|
fn is_text_input(&self) -> bool;
|
||||||
|
|
||||||
/// Whether this element serve as a container of editable text for a text input.
|
|
||||||
fn is_text_control_inner_editor(&self) -> bool;
|
|
||||||
fn text_content(self) -> Cow<'dom, str>;
|
fn text_content(self) -> Cow<'dom, str>;
|
||||||
fn selection(self) -> Option<Range<usize>>;
|
fn selection(self) -> Option<Range<usize>>;
|
||||||
fn image_url(self) -> Option<ServoUrl>;
|
fn image_url(self) -> Option<ServoUrl>;
|
||||||
|
@ -1679,11 +1661,6 @@ impl<'dom> LayoutNodeHelpers<'dom> for LayoutDom<'dom, Node> {
|
||||||
(*self).is::<Element>()
|
(*self).is::<Element>()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_text_node_for_layout(&self) -> bool {
|
|
||||||
self.type_id_for_layout() ==
|
|
||||||
NodeTypeId::CharacterData(CharacterDataTypeId::Text(TextTypeId::Text))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn composed_parent_node_ref(self) -> Option<LayoutDom<'dom, Node>> {
|
fn composed_parent_node_ref(self) -> Option<LayoutDom<'dom, Node>> {
|
||||||
let parent = self.parent_node_ref();
|
let parent = self.parent_node_ref();
|
||||||
|
@ -1825,8 +1802,8 @@ impl<'dom> LayoutNodeHelpers<'dom> for LayoutDom<'dom, Node> {
|
||||||
{
|
{
|
||||||
let input = self.unsafe_get().downcast::<HTMLInputElement>().unwrap();
|
let input = self.unsafe_get().downcast::<HTMLInputElement>().unwrap();
|
||||||
|
|
||||||
// FIXME: All the non-color and non-text input types currently render as text
|
// FIXME: All the non-color input types currently render as text
|
||||||
!matches!(input.input_type(), InputType::Color | InputType::Text)
|
input.input_type() != InputType::Color
|
||||||
} else {
|
} else {
|
||||||
type_id ==
|
type_id ==
|
||||||
NodeTypeId::Element(ElementTypeId::HTMLElement(
|
NodeTypeId::Element(ElementTypeId::HTMLElement(
|
||||||
|
@ -1835,10 +1812,6 @@ impl<'dom> LayoutNodeHelpers<'dom> for LayoutDom<'dom, Node> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_text_control_inner_editor(&self) -> bool {
|
|
||||||
self.unsafe_get().is_text_control_inner_editor()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn text_content(self) -> Cow<'dom, str> {
|
fn text_content(self) -> Cow<'dom, str> {
|
||||||
if let Some(text) = self.downcast::<Text>() {
|
if let Some(text) = self.downcast::<Text>() {
|
||||||
return text.upcast().data_for_layout().into();
|
return text.upcast().data_for_layout().into();
|
||||||
|
@ -1856,25 +1829,6 @@ impl<'dom> LayoutNodeHelpers<'dom> for LayoutDom<'dom, Node> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn selection(self) -> Option<Range<usize>> {
|
fn selection(self) -> Option<Range<usize>> {
|
||||||
// This node is a text node of a text control inner editor in a <input> or <textarea> element.
|
|
||||||
// So we should find those corresponding element, and get its selection.
|
|
||||||
if self.is_text_node_for_layout() &&
|
|
||||||
self.parent_node_ref()
|
|
||||||
.is_some_and(|parent| parent.is_text_control_inner_editor())
|
|
||||||
{
|
|
||||||
let shadow_root = self.containing_shadow_root_for_layout();
|
|
||||||
if let Some(containing_shadow_host) = shadow_root.map(|root| root.get_host_for_layout())
|
|
||||||
{
|
|
||||||
if let Some(area) = containing_shadow_host.downcast::<HTMLTextAreaElement>() {
|
|
||||||
return area.selection_for_layout();
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(input) = containing_shadow_host.downcast::<HTMLInputElement>() {
|
|
||||||
return input.selection_for_layout();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(area) = self.downcast::<HTMLTextAreaElement>() {
|
if let Some(area) = self.downcast::<HTMLTextAreaElement>() {
|
||||||
return area.selection_for_layout();
|
return area.selection_for_layout();
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,7 @@ use style::selector_parser::PseudoElement;
|
||||||
use super::{
|
use super::{
|
||||||
ServoLayoutDocument, ServoLayoutElement, ServoShadowRoot, ServoThreadSafeLayoutElement,
|
ServoLayoutDocument, ServoLayoutElement, ServoShadowRoot, ServoThreadSafeLayoutElement,
|
||||||
};
|
};
|
||||||
use crate::dom::bindings::inheritance::NodeTypeId;
|
use crate::dom::bindings::inheritance::{CharacterDataTypeId, NodeTypeId, TextTypeId};
|
||||||
use crate::dom::bindings::root::LayoutDom;
|
use crate::dom::bindings::root::LayoutDom;
|
||||||
use crate::dom::element::{Element, LayoutElementHelpers};
|
use crate::dom::element::{Element, LayoutElementHelpers};
|
||||||
use crate::dom::node::{LayoutNodeHelpers, Node, NodeFlags, NodeTypeIdWrapper};
|
use crate::dom::node::{LayoutNodeHelpers, Node, NodeFlags, NodeTypeIdWrapper};
|
||||||
|
@ -100,10 +100,6 @@ impl<'dom> ServoLayoutNode<'dom> {
|
||||||
pub fn is_text_input(&self) -> bool {
|
pub fn is_text_input(&self) -> bool {
|
||||||
self.node.is_text_input()
|
self.node.is_text_input()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_text_control_inner_editor(&self) -> bool {
|
|
||||||
self.node.is_text_control_inner_editor()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl style::dom::NodeInfo for ServoLayoutNode<'_> {
|
impl style::dom::NodeInfo for ServoLayoutNode<'_> {
|
||||||
|
@ -112,7 +108,8 @@ impl style::dom::NodeInfo for ServoLayoutNode<'_> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_text_node(&self) -> bool {
|
fn is_text_node(&self) -> bool {
|
||||||
self.node.is_text_node_for_layout()
|
self.script_type_id() ==
|
||||||
|
NodeTypeId::CharacterData(CharacterDataTypeId::Text(TextTypeId::Text))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
[form-action-src-default-ignored.sub.html]
|
|
||||||
[Expecting logs: ["PASS","TEST COMPLETE"\]]
|
|
||||||
expected: FAIL
|
|
|
@ -1,2 +0,0 @@
|
||||||
[spelling-markers-009.html]
|
|
||||||
expected: FAIL
|
|
|
@ -1,2 +0,0 @@
|
||||||
[spelling-markers-010.html]
|
|
||||||
expected: FAIL
|
|
112
tests/wpt/mozilla/meta/MANIFEST.json
vendored
112
tests/wpt/mozilla/meta/MANIFEST.json
vendored
|
@ -91,86 +91,6 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"reftest": {
|
"reftest": {
|
||||||
"appearance": {
|
|
||||||
"input-text-definite-width.html": [
|
|
||||||
"fda46f8af9c14cef3911ec809054624204848b9d",
|
|
||||||
[
|
|
||||||
"appearance/input-text-definite-width.html",
|
|
||||||
[
|
|
||||||
[
|
|
||||||
"/_mozilla/appearance/input-text-definite-width-ref.html",
|
|
||||||
"=="
|
|
||||||
]
|
|
||||||
],
|
|
||||||
{}
|
|
||||||
]
|
|
||||||
],
|
|
||||||
"input-text-empty.html": [
|
|
||||||
"bd5f5f5a21ec0ce028922a6764de41dc904a1eb1",
|
|
||||||
[
|
|
||||||
"appearance/input-text-empty.html",
|
|
||||||
[
|
|
||||||
[
|
|
||||||
"/_mozilla/appearance/input-text-empty-ref.html",
|
|
||||||
"=="
|
|
||||||
]
|
|
||||||
],
|
|
||||||
{}
|
|
||||||
]
|
|
||||||
],
|
|
||||||
"input-text-nonempty-placeholder.html": [
|
|
||||||
"e075663cb6ae708b313b3cd5cd69f78c51b4bc1f",
|
|
||||||
[
|
|
||||||
"appearance/input-text-nonempty-placeholder.html",
|
|
||||||
[
|
|
||||||
[
|
|
||||||
"/_mozilla/appearance/input-text-nonempty-placeholder-ref.html",
|
|
||||||
"=="
|
|
||||||
]
|
|
||||||
],
|
|
||||||
{}
|
|
||||||
]
|
|
||||||
],
|
|
||||||
"input-text-overflow.html": [
|
|
||||||
"52db07c0f0274d2b7b086d7017982145c25918da",
|
|
||||||
[
|
|
||||||
"appearance/input-text-overflow.html",
|
|
||||||
[
|
|
||||||
[
|
|
||||||
"/_mozilla/appearance/input-text-overflow-ref.html",
|
|
||||||
"=="
|
|
||||||
]
|
|
||||||
],
|
|
||||||
{}
|
|
||||||
]
|
|
||||||
],
|
|
||||||
"input-text-placeholder-overflow.html": [
|
|
||||||
"c4d77ae2a22a5b7972f2798b8ca78742b81bacc4",
|
|
||||||
[
|
|
||||||
"appearance/input-text-placeholder-overflow.html",
|
|
||||||
[
|
|
||||||
[
|
|
||||||
"/_mozilla/appearance/input-text-placeholder-overflow-ref.html",
|
|
||||||
"=="
|
|
||||||
]
|
|
||||||
],
|
|
||||||
{}
|
|
||||||
]
|
|
||||||
],
|
|
||||||
"input-text-placeholder.html": [
|
|
||||||
"d75acade78038b14529135b1d63c0ac5a168a87b",
|
|
||||||
[
|
|
||||||
"appearance/input-text-placeholder.html",
|
|
||||||
[
|
|
||||||
[
|
|
||||||
"/_mozilla/appearance/input-text-placeholder-ref.html",
|
|
||||||
"=="
|
|
||||||
]
|
|
||||||
],
|
|
||||||
{}
|
|
||||||
]
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"css": {
|
"css": {
|
||||||
"abs-overflow-stackingcontext.html": [
|
"abs-overflow-stackingcontext.html": [
|
||||||
"264df01aa64e0abe9ea3a75e57452c27d53a904f",
|
"264df01aa64e0abe9ea3a75e57452c27d53a904f",
|
||||||
|
@ -8155,38 +8075,6 @@
|
||||||
"b485d435a63ada28eabe976b49a8a580725e7508",
|
"b485d435a63ada28eabe976b49a8a580725e7508",
|
||||||
[]
|
[]
|
||||||
],
|
],
|
||||||
"appearance": {
|
|
||||||
"input-text-definite-width-ref.html": [
|
|
||||||
"86f7937755750261ed3b06dfe11e78a251b9d175",
|
|
||||||
[]
|
|
||||||
],
|
|
||||||
"input-text-empty-ref.html": [
|
|
||||||
"437c9988a13e094d870f67c8de0dd0becdeece76",
|
|
||||||
[]
|
|
||||||
],
|
|
||||||
"input-text-nonempty-placeholder-ref.html": [
|
|
||||||
"5415dfb2a4a88dc3bfed6ad04e23f288534351e4",
|
|
||||||
[]
|
|
||||||
],
|
|
||||||
"input-text-overflow-ref.html": [
|
|
||||||
"4cece657a2a09cfe3f1d91d49f0c9d76f5714516",
|
|
||||||
[]
|
|
||||||
],
|
|
||||||
"input-text-placeholder-overflow-ref.html": [
|
|
||||||
"0cccfff638c0d8687a3582310c73233b7d883b1a",
|
|
||||||
[]
|
|
||||||
],
|
|
||||||
"input-text-placeholder-ref.html": [
|
|
||||||
"fa5b60bdabdf2b9b818ebe66bfc7f2711173b88b",
|
|
||||||
[]
|
|
||||||
],
|
|
||||||
"supports": {
|
|
||||||
"input-text-ref.css": [
|
|
||||||
"8cf00d493138285e50aa510273abae98c099ae8b",
|
|
||||||
[]
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"bluetooth": {
|
"bluetooth": {
|
||||||
"bluetooth-helpers.js": [
|
"bluetooth-helpers.js": [
|
||||||
"16a280cca298bcaa5796b36b48d331bfd15baae8",
|
"16a280cca298bcaa5796b36b48d331bfd15baae8",
|
||||||
|
|
|
@ -1,2 +0,0 @@
|
||||||
[input_placeholder.html]
|
|
||||||
expected: FAIL
|
|
|
@ -1,15 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title>Appearance of an Input type=text With a Definite Width</title>
|
|
||||||
<link rel="stylesheet" href="./supports/input-text-ref.css">
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
Display of an input type=text should match the display generated by the CSS reference.
|
|
||||||
<div>
|
|
||||||
<div id="input" class="definite-width">
|
|
||||||
Foo
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
|
@ -1,14 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title>Appearance of an Input type=text With a Definite Width</title>
|
|
||||||
<link rel="match" href="input-text-definite-width-ref.html">
|
|
||||||
<link rel="help" href="https://github.com/servo/servo/pull/37065">
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
Display of an input type=text should match the display generated by the CSS reference.
|
|
||||||
<div>
|
|
||||||
<input type="text" value="Foo" style="font-size: 1em !important; width: 100px;"></input>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
|
@ -1,15 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title>Appearance of an Empty Input type=text With a Definite Width</title>
|
|
||||||
<link rel="stylesheet" href="./supports/input-text-ref.css">
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
Display of an input type=text should match the display generated by the CSS reference.
|
|
||||||
<div>
|
|
||||||
<div id="input" class="definite-width">
|
|
||||||
<br>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
|
@ -1,14 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title>Appearance of an Empty Input type=text With a Definite Width</title>
|
|
||||||
<link rel="match" href="input-text-empty-ref.html">
|
|
||||||
<link rel="help" href="https://github.com/servo/servo/pull/37065">
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
Display of an input type=text should match the display generated by the CSS reference.
|
|
||||||
<div>
|
|
||||||
<input type="text" style="font-size: 1em !important; width: 100px;"></input>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
|
@ -1,15 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title>Appearance of a Non-empty Input type=text With a Definite Width and a Placeholder</title>
|
|
||||||
<link rel="stylesheet" href="./supports/input-text-ref.css">
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
Display of an input type=text should match the display generated by the CSS reference.
|
|
||||||
<div>
|
|
||||||
<div id="input" class="definite-width">
|
|
||||||
Foo
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
|
@ -1,14 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title>Appearance of a Non-empty Input type=text With a Definite Width and a Placeholder</title>
|
|
||||||
<link rel="match" href="input-text-nonempty-placeholder-ref.html">
|
|
||||||
<link rel="help" href="https://github.com/servo/servo/pull/37065">
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
Display of an input type=text should match the display generated by the CSS reference.
|
|
||||||
<div>
|
|
||||||
<input type="text" value="Foo" placeholder="Bar" style="font-size: 1em !important; width: 100px;"></input>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
|
@ -1,15 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title>Appearance of an Overflowing Input type=text With a Definite Width</title>
|
|
||||||
<link rel="stylesheet" href="./supports/input-text-ref.css">
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
Display of an input type=text should match the display generated by the CSS reference.
|
|
||||||
<div>
|
|
||||||
<div id="input" class="definite-width">
|
|
||||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
|
@ -1,14 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title>Appearance of an Overflowing Input type=text With a Definite Width</title>
|
|
||||||
<link rel="match" href="input-text-overflow-ref.html">
|
|
||||||
<link rel="help" href="https://github.com/servo/servo/pull/37065">
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
Display of an input type=text should match the display generated by the CSS reference.
|
|
||||||
<div>
|
|
||||||
<input type="text" value="Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua." style="font-size: 1em !important; width: 100px;"></input>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
|
@ -1,15 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title>Appearance of an Input type=text With a Definite Width and an Overflowing Placeholder</title>
|
|
||||||
<link rel="stylesheet" href="./supports/input-text-ref.css">
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
Display of an input type=text should match the display generated by the CSS reference.
|
|
||||||
<div>
|
|
||||||
<div id="input" class="definite-width placeholder-color">
|
|
||||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
|
@ -1,14 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title>Appearance of an Input type=text With a Definite Width and an Overflowing Placeholder</title>
|
|
||||||
<link rel="match" href="input-text-placeholder-overflow-ref.html">
|
|
||||||
<link rel="help" href="https://github.com/servo/servo/pull/37065">
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
Display of an input type=text should match the display generated by the CSS reference.
|
|
||||||
<div>
|
|
||||||
<input type="text" placeholder="Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua." style="font-size: 1em !important; width: 100px;"></input>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
|
@ -1,15 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title>Appearance of an Input type=text With a Definite Width and a Placeholder</title>
|
|
||||||
<link rel="stylesheet" href="./supports/input-text-ref.css">
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
Display of an input type=text should match the display generated by the CSS reference.
|
|
||||||
<div>
|
|
||||||
<div id="input" class="definite-width placeholder-color">
|
|
||||||
Bar
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
|
@ -1,14 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title>Appearance of an Input type=text With a Definite Width and a Placeholder</title>
|
|
||||||
<link rel="match" href="input-text-placeholder-ref.html">
|
|
||||||
<link rel="help" href="https://github.com/servo/servo/pull/37065">
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
Display of an input type=text should match the display generated by the CSS reference.
|
|
||||||
<div>
|
|
||||||
<input type="text" placeholder="Bar" style="font-size: 1em !important; width: 100px;"></input>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
|
@ -1,27 +0,0 @@
|
||||||
/* Minimal stylesheet to mimic the appearence of an input type=text specific to Servo.
|
|
||||||
* This stylesheet is expected to be modified following the development of the
|
|
||||||
* Shadow DOM input type=text in Servo.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#input {
|
|
||||||
display: inline-block;
|
|
||||||
background: white;
|
|
||||||
border: solid lightgrey 1px;
|
|
||||||
font-family: sans-serif;
|
|
||||||
font-size: 1em; /* We are using 1em here to reduce the effect of inconsistencies in layout */
|
|
||||||
overflow: hidden;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* We are using definite width for most of the test to reduce the effect if calculating inline
|
|
||||||
* size of the input element. Which, will depends on the average character width of a font.
|
|
||||||
*
|
|
||||||
* <https://html.spec.whatwg.org/#converting-a-character-width-to-pixels>
|
|
||||||
*/
|
|
||||||
.definite-width {
|
|
||||||
width: 100px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.placeholder-color {
|
|
||||||
color: grey;
|
|
||||||
}
|
|
Loading…
Add table
Add a link
Reference in a new issue