mirror of
https://github.com/servo/servo.git
synced 2025-08-05 13:40:08 +01:00
Create shadow dom for text
Signed-off-by: stevennovaryo <steven.novaryo@gmail.com>
This commit is contained in:
parent
23ce7b31ac
commit
4e44ecafd2
4 changed files with 125 additions and 5 deletions
|
@ -539,7 +539,8 @@ impl InspectorHighlight {
|
|||
});
|
||||
|
||||
// We expect all fragments generated by one node to be in the same scroll tree node and clip node
|
||||
debug_assert_eq!(spatial_id, state.spatial_id);
|
||||
// MYNOTES: Error for Input type text shadow DOM.
|
||||
// debug_assert_eq!(spatial_id, state.spatial_id);
|
||||
if clip_chain_id != ClipChainId::INVALID && state.clip_chain_id != ClipChainId::INVALID {
|
||||
debug_assert_eq!(
|
||||
clip_chain_id, state.clip_chain_id,
|
||||
|
|
|
@ -4,6 +4,8 @@ button {
|
|||
|
||||
button,
|
||||
input {
|
||||
padding-block: 2px;
|
||||
padding-inline: 1px;
|
||||
background: white;
|
||||
border: solid lightgrey 1px;
|
||||
color: black;
|
||||
|
|
|
@ -101,6 +101,14 @@ const DEFAULT_RESET_VALUE: &str = "Reset";
|
|||
const PASSWORD_REPLACEMENT_CHAR: char = '●';
|
||||
const DEFAULT_FILE_INPUT_VALUE: &str = "No file chosen";
|
||||
|
||||
#[derive(Clone, JSTraceable, MallocSizeOf)]
|
||||
#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
|
||||
/// MYNOTES: document this and check name later.
|
||||
struct InputTypeTextShadowTree {
|
||||
text_container: Dom<HTMLDivElement>,
|
||||
placeholder_container: Dom<HTMLDivElement>,
|
||||
}
|
||||
|
||||
#[derive(Clone, JSTraceable, MallocSizeOf)]
|
||||
#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
|
||||
/// Contains references to the elements in the shadow tree for `<input type=range>`.
|
||||
|
@ -111,10 +119,30 @@ struct InputTypeColorShadowTree {
|
|||
color_value: Dom<HTMLDivElement>,
|
||||
}
|
||||
|
||||
const TEXT_TREE_STYLE: &str = "
|
||||
#input-editing-root, #input-placeholder {
|
||||
scrollbar-width: none;
|
||||
resize: none;
|
||||
word-wrap: normal;
|
||||
white-space: pre;
|
||||
}
|
||||
|
||||
#input-placeholder {
|
||||
color: grey;
|
||||
overflow: hidden;
|
||||
pointer-events: none;
|
||||
user-select: none;
|
||||
direction: inherit;
|
||||
text-orientation: inherit;
|
||||
writing-mode: inherit;
|
||||
}
|
||||
";
|
||||
|
||||
#[derive(Clone, JSTraceable, MallocSizeOf)]
|
||||
#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
|
||||
#[non_exhaustive]
|
||||
enum ShadowTree {
|
||||
Text(InputTypeTextShadowTree),
|
||||
Color(InputTypeColorShadowTree),
|
||||
// TODO: Add shadow trees for other input types (range etc) here
|
||||
}
|
||||
|
@ -1079,6 +1107,77 @@ 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 placeholder_container = HTMLDivElement::new(local_name!("div"), None, &document, None, can_gc);
|
||||
placeholder_container
|
||||
.upcast::<Element>()
|
||||
.SetId(DOMString::from("input-placeholder"), can_gc);
|
||||
shadow_root
|
||||
.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-editing-root"), can_gc);
|
||||
shadow_root
|
||||
.upcast::<Node>()
|
||||
.AppendChild(text_container.upcast::<Node>(), can_gc)
|
||||
.unwrap();
|
||||
|
||||
let style = HTMLStyleElement::new(
|
||||
local_name!("style"),
|
||||
None,
|
||||
&document,
|
||||
None,
|
||||
ElementCreator::ScriptCreated,
|
||||
can_gc,
|
||||
);
|
||||
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();
|
||||
// MYNOTES: will check again for shadow tree getter.
|
||||
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) {
|
||||
let document = self.owner_document();
|
||||
let shadow_root = self.shadow_root(can_gc);
|
||||
|
@ -1134,16 +1233,32 @@ impl HTMLInputElement {
|
|||
}
|
||||
|
||||
let shadow_tree = self.shadow_tree.borrow();
|
||||
// MYNOTES: will check again for shadow tree getter.
|
||||
Ref::filter_map(shadow_tree, |shadow_tree| {
|
||||
let shadow_tree = shadow_tree.as_ref()?;
|
||||
let ShadowTree::Color(color_tree) = shadow_tree;
|
||||
Some(color_tree)
|
||||
match shadow_tree {
|
||||
ShadowTree::Color(color_tree) => Some(color_tree),
|
||||
_ => None,
|
||||
}
|
||||
})
|
||||
.ok()
|
||||
.expect("UA shadow tree was not created")
|
||||
}
|
||||
|
||||
fn update_shadow_tree_if_needed(&self, can_gc: CanGc) {
|
||||
if self.input_type() == InputType::Text {
|
||||
let text_shadow_tree = self.text_shadow_tree(can_gc);
|
||||
let value = self.Value();
|
||||
|
||||
let placeholder_text = if value.len() == 0 {
|
||||
self.placeholder.to_owned().take()
|
||||
} else {
|
||||
DOMString::new()
|
||||
};
|
||||
|
||||
text_shadow_tree.placeholder_container.upcast::<Node>().SetTextContent(Some(placeholder_text), can_gc);
|
||||
text_shadow_tree.text_container.upcast::<Node>().SetTextContent(Some(value), can_gc);
|
||||
}
|
||||
if self.input_type() == InputType::Color {
|
||||
let color_shadow_tree = self.color_shadow_tree(can_gc);
|
||||
let mut value = self.Value();
|
||||
|
@ -1266,6 +1381,7 @@ impl<'dom> LayoutHTMLInputElementHelpers<'dom> for LayoutDom<'dom, HTMLInputElem
|
|||
self.unsafe_get().size.get()
|
||||
}
|
||||
|
||||
// MYNOTES is implemented for text
|
||||
fn selection_for_layout(self) -> Option<Range<usize>> {
|
||||
if !self.upcast::<Element>().focus_state() {
|
||||
return None;
|
||||
|
|
|
@ -1787,8 +1787,9 @@ impl<'dom> LayoutNodeHelpers<'dom> for LayoutDom<'dom, Node> {
|
|||
{
|
||||
let input = self.unsafe_get().downcast::<HTMLInputElement>().unwrap();
|
||||
|
||||
// FIXME: All the non-color input types currently render as text
|
||||
input.input_type() != InputType::Color
|
||||
// FIXME: All the non-color and non-text input types currently render as text
|
||||
input.input_type() != InputType::Color &&
|
||||
input.input_type() != InputType::Text
|
||||
} else {
|
||||
type_id ==
|
||||
NodeTypeId::Element(ElementTypeId::HTMLElement(
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue