style: Use Servo for the representation of grid template areas.

Right now we do a lot of useless string copying. In order to avoid transcoding
to utf-16 during layout, make sure to use nsCString at a few related places.

I may revisit this since we're storing other line names as atoms in some places.
So it may be better to just use atoms everywhere.

But that'd be a different patch either way.

Differential Revision: https://phabricator.services.mozilla.com/D35117
This commit is contained in:
Emilio Cobos Álvarez 2019-06-18 22:29:58 +00:00
parent e8271ee926
commit 6cb588d2b5
No known key found for this signature in database
GPG key ID: E1152D0994E4BF8A
4 changed files with 68 additions and 130 deletions

View file

@ -308,11 +308,6 @@ impl_threadsafe_refcount!(
bindings::Gecko_AddRefnsIURIArbitraryThread,
bindings::Gecko_ReleasensIURIArbitraryThread
);
impl_threadsafe_refcount!(
structs::mozilla::css::GridTemplateAreasValue,
bindings::Gecko_AddRefGridTemplateAreasValueArbitraryThread,
bindings::Gecko_ReleaseGridTemplateAreasValueArbitraryThread
);
impl_threadsafe_refcount!(
structs::SharedFontList,
bindings::Gecko_AddRefSharedFontListArbitraryThread,
@ -328,6 +323,7 @@ impl_threadsafe_refcount!(
unsafe fn addref_atom(atom: *mut structs::nsAtom) {
mem::forget(Atom::from_raw(atom));
}
#[inline]
unsafe fn release_atom(atom: *mut structs::nsAtom) {
let _ = Atom::from_addrefed(atom);

View file

@ -1083,8 +1083,8 @@ fn static_assert() {
align-content justify-content align-self
justify-self align-items justify-items
grid-auto-rows grid-auto-columns
grid-auto-flow grid-template-areas
grid-template-rows grid-template-columns">
grid-auto-flow grid-template-rows
grid-template-columns">
% for side in SIDES:
<% impl_split_style_coord(side.ident, "mOffset", side.index) %>
% endfor
@ -1136,13 +1136,19 @@ fn static_assert() {
pub fn set_${value.name}(&mut self, v: longhands::${value.name}::computed_value::T) {
use crate::gecko_bindings::structs::{nsStyleGridLine_kMinLine, nsStyleGridLine_kMaxLine};
let ident = v.ident.as_ref().map_or(&[] as &[_], |ident| ident.0.as_slice());
self.gecko.${value.gecko}.mLineName.assign(ident);
self.gecko.${value.gecko}.mHasSpan = v.is_span;
let line = &mut self.gecko.${value.gecko};
let line_name = &mut line.mLineName;
match v.ident.as_ref() {
Some(i) => i.0.with_str(|s| line_name.assign(s)),
None => line_name.assign(""),
};
line.mHasSpan = v.is_span;
if let Some(integer) = v.line_num {
// clamping the integer between a range
self.gecko.${value.gecko}.mInteger = cmp::max(nsStyleGridLine_kMinLine,
cmp::min(integer, nsStyleGridLine_kMaxLine));
line.mInteger = cmp::max(
nsStyleGridLine_kMinLine,
cmp::min(integer, nsStyleGridLine_kMaxLine),
);
}
}
@ -1205,20 +1211,20 @@ fn static_assert() {
pub fn set_grid_template_${kind}(&mut self, v: longhands::grid_template_${kind}::computed_value::T) {
<% self_grid = "self.gecko.mGridTemplate%s" % kind.title() %>
use crate::gecko_bindings::structs::{nsTArray, nsStyleGridLine_kMaxLine};
use nsstring::nsString;
use nsstring::nsCString;
use std::usize;
use crate::values::CustomIdent;
use crate::values::generics::grid::TrackListType::Auto;
use crate::values::generics::grid::{GridTemplateComponent, RepeatCount};
#[inline]
fn set_line_names(servo_names: &[CustomIdent], gecko_names: &mut nsTArray<nsString>) {
fn set_line_names(servo_names: &[CustomIdent], gecko_names: &mut nsTArray<nsCString>) {
unsafe {
bindings::Gecko_ResizeTArrayForStrings(gecko_names, servo_names.len() as u32);
bindings::Gecko_ResizeTArrayForCStrings(gecko_names, servo_names.len() as u32);
}
for (servo_name, gecko_name) in servo_names.iter().zip(gecko_names.iter_mut()) {
gecko_name.assign(servo_name.0.as_slice());
servo_name.0.with_str(|s| gecko_name.assign(s))
}
}
@ -1256,9 +1262,9 @@ fn static_assert() {
auto_track_size = Some(auto_repeat.track_sizes.get(0).unwrap().clone());
} else {
unsafe {
bindings::Gecko_ResizeTArrayForStrings(
bindings::Gecko_ResizeTArrayForCStrings(
&mut value.mRepeatAutoLineNameListBefore, 0);
bindings::Gecko_ResizeTArrayForStrings(
bindings::Gecko_ResizeTArrayForCStrings(
&mut value.mRepeatAutoLineNameListAfter, 0);
}
}
@ -1332,7 +1338,7 @@ fn static_assert() {
pub fn clone_grid_template_${kind}(&self) -> longhands::grid_template_${kind}::computed_value::T {
<% self_grid = "self.gecko.mGridTemplate%s" % kind.title() %>
use crate::gecko_bindings::structs::nsTArray;
use nsstring::nsString;
use nsstring::nsCString;
use crate::values::CustomIdent;
use crate::values::generics::grid::{GridTemplateComponent, LineNameList, RepeatCount};
use crate::values::generics::grid::{TrackList, TrackListType, TrackListValue, TrackRepeat, TrackSize};
@ -1343,15 +1349,15 @@ fn static_assert() {
};
#[inline]
fn to_boxed_customident_slice(gecko_names: &nsTArray<nsString>) -> Box<[CustomIdent]> {
fn to_boxed_customident_slice(gecko_names: &nsTArray<nsCString>) -> Box<[CustomIdent]> {
let idents: Vec<CustomIdent> = gecko_names.iter().map(|gecko_name| {
CustomIdent(Atom::from(gecko_name.to_string()))
CustomIdent(Atom::from(unsafe { gecko_name.as_str_unchecked() }))
}).collect();
idents.into_boxed_slice()
}
#[inline]
fn to_line_names_vec(gecko_line_names: &nsTArray<nsTArray<nsString>>)
fn to_line_names_vec(gecko_line_names: &nsTArray<nsTArray<nsCString>>)
-> Vec<Box<[CustomIdent]>> {
gecko_line_names.iter().map(|gecko_names| {
to_boxed_customident_slice(gecko_names)
@ -1415,88 +1421,6 @@ fn static_assert() {
% endfor
${impl_simple_type_with_conversion("grid_auto_flow")}
pub fn set_grid_template_areas(&mut self, v: values::computed::position::GridTemplateAreas) {
use crate::gecko_bindings::bindings::Gecko_NewGridTemplateAreasValue;
use crate::gecko_bindings::sugar::refptr::UniqueRefPtr;
let v = match v {
Either::First(areas) => areas,
Either::Second(_) => {
unsafe { self.gecko.mGridTemplateAreas.clear() }
return;
},
};
let mut refptr = unsafe {
UniqueRefPtr::from_addrefed(
Gecko_NewGridTemplateAreasValue(v.0.areas.len() as u32, v.0.strings.len() as u32, v.0.width))
};
for (servo, gecko) in v.0.areas.iter().zip(refptr.mNamedAreas.iter_mut()) {
gecko.mName.assign_str(&*servo.name);
gecko.mColumnStart = servo.columns.start;
gecko.mColumnEnd = servo.columns.end;
gecko.mRowStart = servo.rows.start;
gecko.mRowEnd = servo.rows.end;
}
for (servo, gecko) in v.0.strings.iter().zip(refptr.mTemplates.iter_mut()) {
gecko.assign_str(&*servo);
}
self.gecko.mGridTemplateAreas.set_move(refptr.get())
}
pub fn copy_grid_template_areas_from(&mut self, other: &Self) {
unsafe { self.gecko.mGridTemplateAreas.set(&other.gecko.mGridTemplateAreas) }
}
pub fn reset_grid_template_areas(&mut self, other: &Self) {
self.copy_grid_template_areas_from(other)
}
pub fn clone_grid_template_areas(&self) -> values::computed::position::GridTemplateAreas {
use crate::values::None_;
use crate::values::specified::position::{NamedArea, TemplateAreas, TemplateAreasArc, UnsignedRange};
if self.gecko.mGridTemplateAreas.mRawPtr.is_null() {
return Either::Second(None_);
}
let gecko_grid_template_areas = self.gecko.mGridTemplateAreas.mRawPtr;
let areas = unsafe {
let vec: Vec<NamedArea> =
(*gecko_grid_template_areas).mNamedAreas.iter().map(|gecko_name_area| {
let name = gecko_name_area.mName.to_string().into();
let rows = UnsignedRange {
start: gecko_name_area.mRowStart,
end: gecko_name_area.mRowEnd
};
let columns = UnsignedRange {
start: gecko_name_area.mColumnStart,
end: gecko_name_area.mColumnEnd
};
NamedArea { name, rows, columns }
}).collect();
vec.into()
};
let strings = unsafe {
let vec: Vec<crate::OwnedStr> =
(*gecko_grid_template_areas).mTemplates.iter().map(|gecko_template| {
gecko_template.to_string().into()
}).collect();
vec.into()
};
let width = unsafe {
(*gecko_grid_template_areas).mNColumns
};
Either::First(TemplateAreasArc(Arc::new(TemplateAreas { areas, strings, width })))
}
</%self:impl_trait>
<% skip_outline_longhands = " ".join("outline-style outline-width".split() +

View file

@ -253,18 +253,17 @@
products="gecko">
use crate::parser::Parse;
use servo_arc::Arc;
use crate::values::{Either, None_};
use crate::values::generics::grid::{TrackSize, TrackList, TrackListType};
use crate::values::generics::grid::{TrackListValue, concat_serialize_idents};
use crate::values::specified::{GridTemplateComponent, GenericGridTemplateComponent};
use crate::values::specified::grid::parse_line_names;
use crate::values::specified::position::{TemplateAreas, TemplateAreasArc};
use crate::values::specified::position::{GridTemplateAreas, TemplateAreas, TemplateAreasArc};
/// Parsing for `<grid-template>` shorthand (also used by `grid` shorthand).
pub fn parse_grid_template<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<(GridTemplateComponent, GridTemplateComponent, Either<TemplateAreasArc, None_>), ParseError<'i>> {
) -> Result<(GridTemplateComponent, GridTemplateComponent, GridTemplateAreas), ParseError<'i>> {
// Other shorthand sub properties also parse the `none` keyword and this shorthand
// should know after this keyword there is nothing to parse. Otherwise it gets
// confused and rejects the sub properties that contains `none`.
@ -275,13 +274,10 @@
% for keyword, rust_type in keywords.items():
if let Ok(x) = input.try(|i| {
if i.try(|i| i.expect_ident_matching("${keyword}")).is_ok() {
if i.is_exhausted() {
return Ok((${rust_type},
${rust_type},
Either::Second(None_)))
} else {
if !i.is_exhausted() {
return Err(());
}
return Ok((${rust_type}, ${rust_type}, GridTemplateAreas::None));
}
Err(())
}) {
@ -342,7 +338,7 @@
};
Ok((GenericGridTemplateComponent::TrackList(template_rows),
template_cols, Either::First(TemplateAreasArc(Arc::new(template_areas)))))
template_cols, GridTemplateAreas::Areas(TemplateAreasArc(Arc::new(template_areas)))))
} else {
let mut template_rows = GridTemplateComponent::parse(context, input)?;
if let GenericGridTemplateComponent::TrackList(ref mut list) = template_rows {
@ -356,7 +352,7 @@
}
input.expect_delim('/')?;
Ok((template_rows, GridTemplateComponent::parse(context, input)?, Either::Second(None_)))
Ok((template_rows, GridTemplateComponent::parse(context, input)?, GridTemplateAreas::None))
}
}
@ -377,18 +373,18 @@
pub fn serialize_grid_template<W>(
template_rows: &GridTemplateComponent,
template_columns: &GridTemplateComponent,
template_areas: &Either<TemplateAreasArc, None_>,
template_areas: &GridTemplateAreas,
dest: &mut CssWriter<W>,
) -> fmt::Result
where
W: Write {
match *template_areas {
Either::Second(_none) => {
GridTemplateAreas::None => {
template_rows.to_css(dest)?;
dest.write_str(" / ")?;
template_columns.to_css(dest)
},
Either::First(ref areas) => {
GridTemplateAreas::Areas(ref areas) => {
// The length of template-area and template-rows values should be equal.
if areas.0.strings.len() != template_rows.track_list_len() {
return Ok(());
@ -485,10 +481,9 @@
products="gecko">
use crate::parser::Parse;
use crate::properties::longhands::{grid_auto_columns, grid_auto_rows, grid_auto_flow};
use crate::values::{Either, None_};
use crate::values::generics::grid::{GridTemplateComponent, TrackListType};
use crate::values::specified::{GenericGridTemplateComponent, TrackSize};
use crate::values::specified::position::{AutoFlow, GridAutoFlow};
use crate::values::specified::position::{AutoFlow, GridAutoFlow, GridTemplateAreas};
pub fn parse_value<'i, 't>(
context: &ParserContext,
@ -496,7 +491,7 @@
) -> Result<Longhands, ParseError<'i>> {
let mut temp_rows = GridTemplateComponent::None;
let mut temp_cols = GridTemplateComponent::None;
let mut temp_areas = Either::Second(None_);
let mut temp_areas = GridTemplateAreas::None;
let mut auto_rows = TrackSize::default();
let mut auto_cols = TrackSize::default();
let mut flow = grid_auto_flow::get_initial_value();
@ -558,7 +553,7 @@
impl<'a> LonghandsToSerialize<'a> {
/// Returns true if other sub properties except template-{rows,columns} are initial.
fn is_grid_template(&self) -> bool {
*self.grid_template_areas == Either::Second(None_) &&
*self.grid_template_areas == GridTemplateAreas::None &&
*self.grid_auto_rows == TrackSize::default() &&
*self.grid_auto_columns == TrackSize::default() &&
*self.grid_auto_flow == grid_auto_flow::get_initial_value()
@ -567,7 +562,7 @@
impl<'a> ToCss for LonghandsToSerialize<'a> {
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result where W: fmt::Write {
if *self.grid_template_areas != Either::Second(None_) ||
if *self.grid_template_areas != GridTemplateAreas::None ||
(*self.grid_template_rows != GridTemplateComponent::None &&
*self.grid_template_columns != GridTemplateComponent::None) ||
self.is_grid_template() {

View file

@ -15,7 +15,6 @@ use crate::values::computed::{Context, Percentage, ToComputedValue};
use crate::values::generics::position::Position as GenericPosition;
use crate::values::generics::position::ZIndex as GenericZIndex;
use crate::values::specified::{AllowQuirks, Integer, LengthPercentage};
use crate::values::{Either, None_};
use crate::Zero;
use cssparser::Parser;
use selectors::parser::SelectorParseErrorKind;
@ -477,6 +476,7 @@ impl From<GridAutoFlow> for u8 {
ToResolvedValue,
ToShmem,
)]
#[repr(C)]
/// https://drafts.csswg.org/css-grid/#named-grid-area
pub struct TemplateAreas {
/// `named area` containing for each template area
@ -599,6 +599,7 @@ impl Parse for TemplateAreas {
ToResolvedValue,
ToShmem,
)]
#[repr(transparent)]
pub struct TemplateAreasArc(#[ignore_malloc_size_of = "Arc"] pub Arc<TemplateAreas>);
impl Parse for TemplateAreasArc {
@ -623,8 +624,9 @@ pub struct UnsignedRange {
}
#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToShmem)]
/// Not associated with any particular grid item, but can
/// be referenced from the grid-placement properties.
#[repr(C)]
/// Not associated with any particular grid item, but can be referenced from the
/// grid-placement properties.
pub struct NamedArea {
/// Name of the `named area`
pub name: crate::OwnedStr,
@ -670,16 +672,37 @@ fn is_name_code_point(c: char) -> bool {
}
/// This property specifies named grid areas.
/// The syntax of this property also provides a visualization of
/// the structure of the grid, making the overall layout of
/// the grid container easier to understand.
pub type GridTemplateAreas = Either<TemplateAreasArc, None_>;
///
/// The syntax of this property also provides a visualization of the structure
/// of the grid, making the overall layout of the grid container easier to
/// understand.
///
/// cbindgen:derive-tagged-enum-copy-constructor=true
#[repr(C, u8)]
#[derive(
Clone,
Debug,
MallocSizeOf,
Parse,
PartialEq,
SpecifiedValueInfo,
ToComputedValue,
ToCss,
ToResolvedValue,
ToShmem,
)]
pub enum GridTemplateAreas {
/// The `none` value.
None,
/// The actual value.
Areas(TemplateAreasArc),
}
impl GridTemplateAreas {
#[inline]
/// Get default value as `none`
pub fn none() -> GridTemplateAreas {
Either::Second(None_)
GridTemplateAreas::None
}
}