Auto merge of #26070 - servo:layout-2020-more-cleanups, r=SimonSapin

Make LayoutNodeHelpers::text_content return a cow

What does it mean? It means that layout can process `Text` nodes' contents by just borrowing them, potentially saving us from a lot of unnecessary tempoorary allocations, which is nice.
This commit is contained in:
bors-servo 2020-03-31 10:51:18 -04:00 committed by GitHub
commit 3aa15e3fa3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 101 additions and 81 deletions

View file

@ -234,27 +234,27 @@ impl Attr {
#[allow(unsafe_code)]
pub trait AttrHelpersForLayout<'dom> {
unsafe fn value(self) -> &'dom AttrValue;
unsafe fn value_ref_forever(self) -> &'dom str;
unsafe fn value_tokens(self) -> Option<&'dom [Atom]>;
unsafe fn local_name_atom(self) -> LocalName;
fn value(self) -> &'dom AttrValue;
fn as_str(self) -> &'dom str;
fn as_tokens(self) -> Option<&'dom [Atom]>;
fn local_name(self) -> &'dom LocalName;
fn namespace(self) -> &'dom Namespace;
}
#[allow(unsafe_code)]
impl<'dom> AttrHelpersForLayout<'dom> for LayoutDom<'dom, Attr> {
#[inline]
unsafe fn value(self) -> &'dom AttrValue {
(*self.unsafe_get()).value.borrow_for_layout()
fn value(self) -> &'dom AttrValue {
unsafe { self.unsafe_get().value.borrow_for_layout() }
}
#[inline]
unsafe fn value_ref_forever(self) -> &'dom str {
fn as_str(self) -> &'dom str {
&**self.value()
}
#[inline]
unsafe fn value_tokens(self) -> Option<&'dom [Atom]> {
// This transmute is used to cheat the lifetime restriction.
fn as_tokens(self) -> Option<&'dom [Atom]> {
match *self.value() {
AttrValue::TokenList(_, ref tokens) => Some(tokens),
_ => None,
@ -262,7 +262,12 @@ impl<'dom> AttrHelpersForLayout<'dom> for LayoutDom<'dom, Attr> {
}
#[inline]
unsafe fn local_name_atom(self) -> LocalName {
(*self.unsafe_get()).identifier.local_name.clone()
fn local_name(self) -> &'dom LocalName {
unsafe { &self.unsafe_get().identifier.local_name }
}
#[inline]
fn namespace(self) -> &'dom Namespace {
unsafe { &self.unsafe_get().identifier.namespace }
}
}

View file

@ -280,16 +280,15 @@ impl CharacterDataMethods for CharacterData {
}
}
#[allow(unsafe_code)]
pub trait LayoutCharacterDataHelpers<'dom> {
unsafe fn data_for_layout(self) -> &'dom str;
fn data_for_layout(self) -> &'dom str;
}
#[allow(unsafe_code)]
impl<'dom> LayoutCharacterDataHelpers<'dom> for LayoutDom<'dom, CharacterData> {
#[allow(unsafe_code)]
#[inline]
unsafe fn data_for_layout(self) -> &'dom str {
&(*self.unsafe_get()).data.borrow_for_layout()
fn data_for_layout(self) -> &'dom str {
unsafe { self.unsafe_get().data.borrow_for_layout() }
}
}

View file

@ -578,7 +578,7 @@ pub unsafe fn get_attr_for_layout<'dom>(
.iter()
.find(|attr| {
let attr = attr.to_layout();
*name == attr.local_name_atom() && (*attr.unsafe_get()).namespace() == namespace
name == attr.local_name() && namespace == attr.namespace()
})
.map(|attr| attr.to_layout())
}
@ -600,7 +600,7 @@ impl RawLayoutElementHelpers for Element {
namespace: &Namespace,
name: &LocalName,
) -> Option<&'a str> {
get_attr_for_layout(self, namespace, name).map(|attr| attr.value_ref_forever())
get_attr_for_layout(self, namespace, name).map(|attr| attr.as_str())
}
#[inline]
@ -610,7 +610,7 @@ impl RawLayoutElementHelpers for Element {
.iter()
.filter_map(|attr| {
let attr = attr.to_layout();
if *name == attr.local_name_atom() {
if name == attr.local_name() {
Some(attr.value())
} else {
None
@ -656,7 +656,7 @@ impl<'dom> LayoutElementHelpers<'dom> for LayoutDom<'dom, Element> {
get_attr_for_layout(&*self.unsafe_get(), &ns!(), &local_name!("class")).map_or(
false,
|attr| {
attr.value_tokens()
attr.as_tokens()
.unwrap()
.iter()
.any(|atom| case_sensitivity.eq_atom(atom, name))
@ -668,7 +668,7 @@ impl<'dom> LayoutElementHelpers<'dom> for LayoutDom<'dom, Element> {
#[inline]
unsafe fn get_classes_for_layout(self) -> Option<&'dom [Atom]> {
get_attr_for_layout(&*self.unsafe_get(), &ns!(), &local_name!("class"))
.map(|attr| attr.value_tokens().unwrap())
.map(|attr| attr.as_tokens().unwrap())
}
#[allow(unsafe_code)]

View file

@ -67,7 +67,7 @@ use profile_traits::ipc;
use script_layout_interface::rpc::TextIndexResponse;
use script_traits::ScriptToConstellationChan;
use servo_atoms::Atom;
use std::borrow::ToOwned;
use std::borrow::Cow;
use std::cell::Cell;
use std::ops::Range;
use std::ptr::NonNull;
@ -705,9 +705,8 @@ impl HTMLInputElement {
}
}
pub trait LayoutHTMLInputElementHelpers {
#[allow(unsafe_code)]
unsafe fn value_for_layout(self) -> String;
pub trait LayoutHTMLInputElementHelpers<'dom> {
fn value_for_layout(self) -> Cow<'dom, str>;
#[allow(unsafe_code)]
unsafe fn size_for_layout(self) -> u32;
#[allow(unsafe_code)]
@ -726,41 +725,47 @@ unsafe fn get_raw_textinput_value(input: LayoutDom<HTMLInputElement>) -> DOMStri
.get_content()
}
impl LayoutHTMLInputElementHelpers for LayoutDom<'_, HTMLInputElement> {
impl<'dom> LayoutHTMLInputElementHelpers<'dom> for LayoutDom<'dom, HTMLInputElement> {
#[allow(unsafe_code)]
unsafe fn value_for_layout(self) -> String {
#[allow(unsafe_code)]
unsafe fn get_raw_attr_value(
input: LayoutDom<'_, HTMLInputElement>,
default: &str,
) -> String {
let elem = input.upcast::<Element>();
let value = (*elem.unsafe_get())
.get_attr_val_for_layout(&ns!(), &local_name!("value"))
.unwrap_or(default);
String::from(value)
fn value_for_layout(self) -> Cow<'dom, str> {
fn get_raw_attr_value<'dom>(
input: LayoutDom<'dom, HTMLInputElement>,
default: &'static str,
) -> Cow<'dom, str> {
unsafe {
input
.upcast::<Element>()
.unsafe_get()
.get_attr_val_for_layout(&ns!(), &local_name!("value"))
.unwrap_or(default)
.into()
}
}
match (*self.unsafe_get()).input_type() {
InputType::Checkbox | InputType::Radio => String::new(),
InputType::File | InputType::Image => String::new(),
let placeholder = unsafe { &**self.unsafe_get().placeholder.borrow_for_layout() };
match unsafe { self.unsafe_get().input_type() } {
InputType::Checkbox | InputType::Radio => "".into(),
InputType::File | InputType::Image => "".into(),
InputType::Button => get_raw_attr_value(self, ""),
InputType::Submit => get_raw_attr_value(self, DEFAULT_SUBMIT_VALUE),
InputType::Reset => get_raw_attr_value(self, DEFAULT_RESET_VALUE),
InputType::Password => {
let text = get_raw_textinput_value(self);
let text = unsafe { get_raw_textinput_value(self) };
if !text.is_empty() {
text.chars().map(|_| PASSWORD_REPLACEMENT_CHAR).collect()
text.chars()
.map(|_| PASSWORD_REPLACEMENT_CHAR)
.collect::<String>()
.into()
} else {
String::from((*self.unsafe_get()).placeholder.borrow_for_layout().clone())
placeholder.into()
}
},
_ => {
let text = get_raw_textinput_value(self);
let text = unsafe { get_raw_textinput_value(self) };
if !text.is_empty() {
String::from(text)
text.into()
} else {
String::from((*self.unsafe_get()).placeholder.borrow_for_layout().clone())
placeholder.into()
}
},
}

View file

@ -56,8 +56,7 @@ pub struct HTMLTextAreaElement {
}
pub trait LayoutHTMLTextAreaElementHelpers {
#[allow(unsafe_code)]
unsafe fn value_for_layout(self) -> String;
fn value_for_layout(self) -> String;
#[allow(unsafe_code)]
unsafe fn selection_for_layout(self) -> Option<Range<usize>>;
#[allow(unsafe_code)]
@ -67,19 +66,19 @@ pub trait LayoutHTMLTextAreaElementHelpers {
}
impl LayoutHTMLTextAreaElementHelpers for LayoutDom<'_, HTMLTextAreaElement> {
#[allow(unrooted_must_root)]
#[allow(unsafe_code)]
unsafe fn value_for_layout(self) -> String {
let text = (*self.unsafe_get())
.textinput
.borrow_for_layout()
.get_content();
if text.is_empty() {
(*self.unsafe_get())
.placeholder
fn value_for_layout(self) -> String {
let text = unsafe {
self.unsafe_get()
.textinput
.borrow_for_layout()
.replace("\r\n", "\n")
.replace("\r", "\n")
.get_content()
};
if text.is_empty() {
let placeholder = unsafe { self.unsafe_get().placeholder.borrow_for_layout() };
// FIXME(nox): Would be cool to not allocate a new string if the
// placeholder is single line, but that's an unimportant detail.
placeholder.replace("\r\n", "\n").replace("\r", "\n").into()
} else {
text.into()
}

View file

@ -87,7 +87,7 @@ use servo_arc::Arc;
use servo_atoms::Atom;
use servo_url::ServoUrl;
use smallvec::SmallVec;
use std::borrow::ToOwned;
use std::borrow::Cow;
use std::cell::{Cell, UnsafeCell};
use std::cmp;
use std::default::Default;
@ -1326,7 +1326,7 @@ pub trait LayoutNodeHelpers<'dom> {
unsafe fn init_style_and_layout_data(self, _: OpaqueStyleAndLayoutData);
unsafe fn take_style_and_layout_data(self) -> OpaqueStyleAndLayoutData;
fn text_content(self) -> String;
fn text_content(self) -> Cow<'dom, str>;
fn selection(self) -> Option<Range<usize>>;
fn image_url(self) -> Option<ServoUrl>;
fn image_density(self) -> Option<f64>;
@ -1456,18 +1456,17 @@ impl<'dom> LayoutNodeHelpers<'dom> for LayoutDom<'dom, Node> {
val
}
#[allow(unsafe_code)]
fn text_content(self) -> String {
fn text_content(self) -> Cow<'dom, str> {
if let Some(text) = self.downcast::<Text>() {
return unsafe { text.upcast().data_for_layout().to_owned() };
return text.upcast().data_for_layout().into();
}
if let Some(input) = self.downcast::<HTMLInputElement>() {
return unsafe { input.value_for_layout() };
return input.value_for_layout();
}
if let Some(area) = self.downcast::<HTMLTextAreaElement>() {
return unsafe { area.value_for_layout() };
return area.value_for_layout().into();
}
panic!("not text!")