Auto merge of #5988 - Ms2ger:preshints, r=pcwalton

<!-- Reviewable:start -->
[<img src="https://reviewable.io/review_button.png" height=40 alt="Review on Reviewable"/>](https://reviewable.io/reviews/servo/servo/5988)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2015-05-12 02:15:11 -05:00
commit 8fa604be9d
4 changed files with 117 additions and 200 deletions

View file

@ -60,7 +60,7 @@ use script::dom::node::{HAS_CHANGED, IS_DIRTY, HAS_DIRTY_SIBLINGS, HAS_DIRTY_DES
use script::dom::text::Text; use script::dom::text::Text;
use script::layout_interface::LayoutChan; use script::layout_interface::LayoutChan;
use msg::constellation_msg::{PipelineId, SubpageId}; use msg::constellation_msg::{PipelineId, SubpageId};
use util::str::{LengthOrPercentageOrAuto, is_whitespace}; use util::str::is_whitespace;
use std::borrow::ToOwned; use std::borrow::ToOwned;
use std::cell::{Ref, RefMut}; use std::cell::{Ref, RefMut};
use std::marker::PhantomData; use std::marker::PhantomData;
@ -71,8 +71,7 @@ use style::computed_values::content::ContentItem;
use style::computed_values::{content, display, white_space}; use style::computed_values::{content, display, white_space};
use selectors::matching::DeclarationBlock; use selectors::matching::DeclarationBlock;
use selectors::parser::{NamespaceConstraint, AttrSelector}; use selectors::parser::{NamespaceConstraint, AttrSelector};
use style::legacy::{IntegerAttribute, LengthAttribute}; use style::legacy::UnsignedIntegerAttribute;
use style::legacy::{UnsignedIntegerAttribute};
use style::node::{TElement, TElementAttributes, TNode}; use style::node::{TElement, TElementAttributes, TNode};
use style::properties::{PropertyDeclaration, PropertyDeclarationBlock}; use style::properties::{PropertyDeclaration, PropertyDeclarationBlock};
use util::smallvec::VecLike; use util::smallvec::VecLike;
@ -657,18 +656,6 @@ impl<'le> TElementAttributes<'le> for LayoutElement<'le> {
} }
} }
fn get_length_attribute(self, length_attribute: LengthAttribute) -> LengthOrPercentageOrAuto {
unsafe {
self.element.get_length_attribute_for_layout(length_attribute)
}
}
fn get_integer_attribute(self, integer_attribute: IntegerAttribute) -> Option<i32> {
unsafe {
self.element.get_integer_attribute_for_layout(integer_attribute)
}
}
fn get_unsigned_integer_attribute(self, attribute: UnsignedIntegerAttribute) -> Option<u32> { fn get_unsigned_integer_attribute(self, attribute: UnsignedIntegerAttribute) -> Option<u32> {
unsafe { unsafe {
self.element.get_unsigned_integer_attribute_for_layout(attribute) self.element.get_unsigned_integer_attribute_for_layout(attribute)

View file

@ -59,10 +59,13 @@ use dom::virtualmethods::{VirtualMethods, vtable_for};
use devtools_traits::AttrInfo; use devtools_traits::AttrInfo;
use style; use style;
use style::legacy::{UnsignedIntegerAttribute, IntegerAttribute, LengthAttribute, from_declaration}; use style::legacy::{UnsignedIntegerAttribute, from_declaration};
use style::properties::{PropertyDeclarationBlock, PropertyDeclaration, parse_style_attribute}; use style::properties::{PropertyDeclarationBlock, PropertyDeclaration, parse_style_attribute};
use style::properties::DeclaredValue::SpecifiedValue; use style::properties::DeclaredValue::SpecifiedValue;
use style::values::specified::CSSColor; use style::properties::longhands::{self, border_spacing};
use style::values::CSSFloat;
use style::values::specified::{self, CSSColor};
use util::geometry::Au;
use util::namespace; use util::namespace;
use util::smallvec::VecLike; use util::smallvec::VecLike;
use util::str::{DOMString, LengthOrPercentageOrAuto}; use util::str::{DOMString, LengthOrPercentageOrAuto};
@ -162,10 +165,6 @@ pub trait RawLayoutElementHelpers {
unsafe fn synthesize_presentational_hints_for_legacy_attributes<V>(&self, &mut V) unsafe fn synthesize_presentational_hints_for_legacy_attributes<V>(&self, &mut V)
where V: VecLike<DeclarationBlock<Vec<PropertyDeclaration>>>; where V: VecLike<DeclarationBlock<Vec<PropertyDeclaration>>>;
unsafe fn get_length_attribute_for_layout(&self, length_attribute: LengthAttribute)
-> LengthOrPercentageOrAuto;
unsafe fn get_integer_attribute_for_layout(&self, integer_attribute: IntegerAttribute)
-> Option<i32>;
unsafe fn get_checked_state_for_layout(&self) -> bool; unsafe fn get_checked_state_for_layout(&self) -> bool;
unsafe fn get_indeterminate_state_for_layout(&self) -> bool; unsafe fn get_indeterminate_state_for_layout(&self) -> bool;
unsafe fn get_unsigned_integer_attribute_for_layout(&self, attribute: UnsignedIntegerAttribute) unsafe fn get_unsigned_integer_attribute_for_layout(&self, attribute: UnsignedIntegerAttribute)
@ -260,51 +259,120 @@ impl RawLayoutElementHelpers for Element {
PropertyDeclaration::BackgroundColor(SpecifiedValue( PropertyDeclaration::BackgroundColor(SpecifiedValue(
CSSColor { parsed: Color::RGBA(color), authored: None })))); CSSColor { parsed: Color::RGBA(color), authored: None }))));
} }
let cellspacing = if self.is_htmltableelement() {
let this: &HTMLTableElement = mem::transmute(self);
this.get_cellspacing()
} else {
None
};
if let Some(cellspacing) = cellspacing {
let width_value = specified::Length::Absolute(Au::from_px(cellspacing as i32));
hints.push(from_declaration(
PropertyDeclaration::BorderSpacing(SpecifiedValue(
border_spacing::SpecifiedValue {
horizontal: width_value,
vertical: width_value,
}))));
} }
#[inline]
unsafe fn get_length_attribute_for_layout(&self, length_attribute: LengthAttribute) let size = if self.is_htmlinputelement() {
-> LengthOrPercentageOrAuto { // FIXME(pcwalton): More use of atoms, please!
match length_attribute { // FIXME(Ms2ger): this is nonsense! Invalid values also end up as
LengthAttribute::Width => { // a text field
if self.is_htmltableelement() { match self.get_attr_val_for_layout(&ns!(""), &atom!("type")) {
Some("text") | Some("password") => {
let this: &HTMLInputElement = mem::transmute(self);
match this.get_size_for_layout() {
0 => None,
s => Some(s as i32),
}
}
_ => None
}
} else {
None
};
if let Some(size) = size {
let value = specified::Length::ServoCharacterWidth(
specified::CharacterWidth(size));
hints.push(from_declaration(
PropertyDeclaration::Width(SpecifiedValue(
specified::LengthOrPercentageOrAuto::Length(value)))));
}
let width = if self.is_htmltableelement() {
let this: &HTMLTableElement = mem::transmute(self); let this: &HTMLTableElement = mem::transmute(self);
this.get_width() this.get_width()
} else if self.is_htmltablecellelement() { } else if self.is_htmltabledatacellelement() {
let this: &HTMLTableCellElement = mem::transmute(self); let this: &HTMLTableCellElement = mem::transmute(self);
this.get_width() this.get_width()
} else { } else {
panic!("I'm not a table or table cell!") LengthOrPercentageOrAuto::Auto
} };
match width {
LengthOrPercentageOrAuto::Auto => {}
LengthOrPercentageOrAuto::Percentage(percentage) => {
let width_value = specified::LengthOrPercentageOrAuto::Percentage(percentage);
hints.push(from_declaration(
PropertyDeclaration::Width(SpecifiedValue(width_value))));
} }
LengthOrPercentageOrAuto::Length(length) => {
let width_value = specified::LengthOrPercentageOrAuto::Length(specified::Length::Absolute(length));
hints.push(from_declaration(
PropertyDeclaration::Width(SpecifiedValue(width_value))));
} }
} }
#[inline]
unsafe fn get_integer_attribute_for_layout(&self, integer_attribute: IntegerAttribute) let cols = if self.is_htmltextareaelement() {
-> Option<i32> {
match integer_attribute {
IntegerAttribute::Size => {
if !self.is_htmlinputelement() {
panic!("I'm not a form input!")
}
let this: &HTMLInputElement = mem::transmute(self);
Some(this.get_size_for_layout() as i32)
}
IntegerAttribute::Cols => {
if !self.is_htmltextareaelement() {
panic!("I'm not a textarea element!")
}
let this: &HTMLTextAreaElement = mem::transmute(self); let this: &HTMLTextAreaElement = mem::transmute(self);
Some(this.get_cols_for_layout() as i32) match this.get_cols_for_layout() {
0 => None,
c => Some(c as i32),
} }
IntegerAttribute::Rows => { } else {
if !self.is_htmltextareaelement() { None
panic!("I'm not a textarea element!") };
if let Some(cols) = cols {
// TODO(mttr) ServoCharacterWidth uses the size math for <input type="text">, but
// the math for <textarea> is a little different since we need to take
// scrollbar size into consideration (but we don't have a scrollbar yet!)
//
// https://html.spec.whatwg.org/multipage/#textarea-effective-width
let value = specified::Length::ServoCharacterWidth(specified::CharacterWidth(cols));
hints.push(from_declaration(
PropertyDeclaration::Width(SpecifiedValue(
specified::LengthOrPercentageOrAuto::Length(value)))));
} }
let rows = if self.is_htmltextareaelement() {
let this: &HTMLTextAreaElement = mem::transmute(self); let this: &HTMLTextAreaElement = mem::transmute(self);
Some(this.get_rows_for_layout() as i32) match this.get_rows_for_layout() {
0 => None,
r => Some(r as i32),
} }
} else {
None
};
if let Some(rows) = rows {
// TODO(mttr) This should take scrollbar size into consideration.
//
// https://html.spec.whatwg.org/multipage/#textarea-effective-height
let value = specified::Length::FontRelative(specified::FontRelativeLength::Em(rows as CSSFloat));
hints.push(from_declaration(
PropertyDeclaration::Height(SpecifiedValue(
longhands::height::SpecifiedValue(
specified::LengthOrPercentageOrAuto::Length(value))))));
} }
} }
@ -345,16 +413,6 @@ impl RawLayoutElementHelpers for Element {
None None
} }
} }
UnsignedIntegerAttribute::CellSpacing => {
if self.is_htmltableelement() {
let this: &HTMLTableElement = mem::transmute(self);
this.get_cellspacing()
} else {
// Don't panic since `display` can cause this to be called on arbitrary
// elements.
None
}
}
UnsignedIntegerAttribute::ColSpan => { UnsignedIntegerAttribute::ColSpan => {
if self.is_htmltablecellelement() { if self.is_htmltablecellelement() {
let this: &HTMLTableCellElement = mem::transmute(self); let this: &HTMLTableCellElement = mem::transmute(self);

View file

@ -10,39 +10,20 @@ use std::sync::Arc;
use selectors::tree::{TElement, TNode}; use selectors::tree::{TElement, TNode};
use selectors::matching::DeclarationBlock; use selectors::matching::DeclarationBlock;
use node::TElementAttributes; use node::TElementAttributes;
use values::{CSSFloat, specified}; use values::specified;
use properties::DeclaredValue::SpecifiedValue; use properties::DeclaredValue::SpecifiedValue;
use properties::PropertyDeclaration; use properties::PropertyDeclaration;
use properties::longhands::{self, border_spacing}; use properties::longhands;
use selector_matching::Stylist; use selector_matching::Stylist;
use util::geometry::Au; use util::geometry::Au;
use util::smallvec::VecLike; use util::smallvec::VecLike;
use util::str::LengthOrPercentageOrAuto;
/// Legacy presentational attributes that take a length as defined in HTML5 § 2.4.4.4.
#[derive(Copy, Clone, PartialEq, Eq)]
pub enum LengthAttribute {
/// `<td width>`
Width,
}
/// Legacy presentational attributes that take an integer as defined in HTML5 § 2.4.4.2.
#[derive(Copy, Clone, PartialEq, Eq)]
pub enum IntegerAttribute {
/// `<input size>`
Size,
Cols,
Rows,
}
/// Legacy presentational attributes that take a nonnegative integer as defined in HTML5 § 2.4.4.2. /// Legacy presentational attributes that take a nonnegative integer as defined in HTML5 § 2.4.4.2.
#[derive(Copy, Clone, PartialEq, Eq)] #[derive(Copy, Clone, PartialEq, Eq)]
pub enum UnsignedIntegerAttribute { pub enum UnsignedIntegerAttribute {
/// `<td border>` /// `<td border>`
Border, Border,
/// `<table cellspacing>`
CellSpacing,
/// `<td colspan>` /// `<td colspan>`
ColSpan, ColSpan,
} }
@ -75,14 +56,6 @@ pub trait PresentationalHintSynthesis {
E: TElement<'a> + E: TElement<'a> +
TElementAttributes<'a>, TElementAttributes<'a>,
V: VecLike<DeclarationBlock<Vec<PropertyDeclaration>>>; V: VecLike<DeclarationBlock<Vec<PropertyDeclaration>>>;
/// Synthesizes rules for the legacy `width` attribute.
fn synthesize_presentational_hint_for_legacy_width_attribute<'a,E,V>(
&self,
element: E,
matching_rules_list: &mut V,
shareable: &mut bool)
where E: TElement<'a> + TElementAttributes<'a>,
V: VecLike<DeclarationBlock<Vec<PropertyDeclaration>>>;
} }
impl PresentationalHintSynthesis for Stylist { impl PresentationalHintSynthesis for Stylist {
@ -105,89 +78,16 @@ impl PresentationalHintSynthesis for Stylist {
match element.get_local_name() { match element.get_local_name() {
name if *name == atom!("td") => { name if *name == atom!("td") => {
self.synthesize_presentational_hint_for_legacy_width_attribute(
element,
matching_rules_list,
shareable);
self.synthesize_presentational_hint_for_legacy_border_attribute( self.synthesize_presentational_hint_for_legacy_border_attribute(
element, element,
matching_rules_list, matching_rules_list,
shareable); shareable);
} }
name if *name == atom!("table") => { name if *name == atom!("table") => {
self.synthesize_presentational_hint_for_legacy_width_attribute(
element,
matching_rules_list,
shareable);
self.synthesize_presentational_hint_for_legacy_border_attribute( self.synthesize_presentational_hint_for_legacy_border_attribute(
element, element,
matching_rules_list, matching_rules_list,
shareable); shareable);
match element.get_unsigned_integer_attribute(
UnsignedIntegerAttribute::CellSpacing) {
None => {}
Some(length) => {
let width_value = specified::Length::Absolute(Au::from_px(length as i32));
matching_rules_list.push(from_declaration(
PropertyDeclaration::BorderSpacing(
SpecifiedValue(
border_spacing::SpecifiedValue {
horizontal: width_value,
vertical: width_value,
}))));
*shareable = false
}
}
}
name if *name == atom!("input") => {
// FIXME(pcwalton): More use of atoms, please!
match element.get_attr(&ns!(""), &atom!("type")) {
Some("text") | Some("password") => {
match element.get_integer_attribute(IntegerAttribute::Size) {
Some(value) if value != 0 => {
let value = specified::Length::ServoCharacterWidth(
specified::CharacterWidth(value));
matching_rules_list.push(from_declaration(
PropertyDeclaration::Width(SpecifiedValue(
specified::LengthOrPercentageOrAuto::Length(value)))));
*shareable = false
}
Some(_) | None => {}
}
}
_ => {}
};
}
name if *name == atom!("textarea") => {
match element.get_integer_attribute(IntegerAttribute::Cols) {
Some(value) if value != 0 => {
// TODO(mttr) ServoCharacterWidth uses the size math for <input type="text">, but
// the math for <textarea> is a little different since we need to take
// scrollbar size into consideration (but we don't have a scrollbar yet!)
//
// https://html.spec.whatwg.org/multipage/#textarea-effective-width
let value = specified::Length::ServoCharacterWidth(specified::CharacterWidth(value));
matching_rules_list.push(from_declaration(
PropertyDeclaration::Width(SpecifiedValue(
specified::LengthOrPercentageOrAuto::Length(value)))));
*shareable = false
}
Some(_) | None => {}
}
match element.get_integer_attribute(IntegerAttribute::Rows) {
Some(value) if value != 0 => {
// TODO(mttr) This should take scrollbar size into consideration.
//
// https://html.spec.whatwg.org/multipage/#textarea-effective-height
let value = specified::Length::FontRelative(specified::FontRelativeLength::Em(value as CSSFloat));
matching_rules_list.push(from_declaration(
PropertyDeclaration::Height(SpecifiedValue(
longhands::height::SpecifiedValue(
specified::LengthOrPercentageOrAuto::Length(value))))));
*shareable = false
}
Some(_) | None => {}
}
} }
_ => {} _ => {}
} }
@ -222,31 +122,6 @@ impl PresentationalHintSynthesis for Stylist {
} }
} }
} }
fn synthesize_presentational_hint_for_legacy_width_attribute<'a,E,V>(
&self,
element: E,
matching_rules_list: &mut V,
shareable: &mut bool)
where E: TElement<'a> + TElementAttributes<'a>,
V: VecLike<DeclarationBlock<Vec<PropertyDeclaration>>> {
match element.get_length_attribute(LengthAttribute::Width) {
LengthOrPercentageOrAuto::Auto => {}
LengthOrPercentageOrAuto::Percentage(percentage) => {
let width_value = specified::LengthOrPercentageOrAuto::Percentage(percentage);
matching_rules_list.push(from_declaration(
PropertyDeclaration::Width(SpecifiedValue(width_value))));
*shareable = false
}
LengthOrPercentageOrAuto::Length(length) => {
let width_value = specified::LengthOrPercentageOrAuto::Length(
specified::Length::Absolute(length));
matching_rules_list.push(from_declaration(
PropertyDeclaration::Width(SpecifiedValue(width_value))));
*shareable = false
}
}
}
} }

View file

@ -5,10 +5,9 @@
//! Traits that nodes must implement. Breaks the otherwise-cyclic dependency between layout and //! Traits that nodes must implement. Breaks the otherwise-cyclic dependency between layout and
//! style. //! style.
use legacy::{IntegerAttribute, LengthAttribute, UnsignedIntegerAttribute}; use legacy::UnsignedIntegerAttribute;
use properties::PropertyDeclaration; use properties::PropertyDeclaration;
use util::smallvec::VecLike; use util::smallvec::VecLike;
use util::str::LengthOrPercentageOrAuto;
use selectors::matching::DeclarationBlock; use selectors::matching::DeclarationBlock;
pub use selectors::tree::{TNode, TElement}; pub use selectors::tree::{TNode, TElement};
@ -17,8 +16,6 @@ use string_cache::{Atom, Namespace};
pub trait TElementAttributes<'a> : Copy { pub trait TElementAttributes<'a> : Copy {
fn synthesize_presentational_hints_for_legacy_attributes<V>(self, &mut V) fn synthesize_presentational_hints_for_legacy_attributes<V>(self, &mut V)
where V: VecLike<DeclarationBlock<Vec<PropertyDeclaration>>>; where V: VecLike<DeclarationBlock<Vec<PropertyDeclaration>>>;
fn get_length_attribute(self, attribute: LengthAttribute) -> LengthOrPercentageOrAuto;
fn get_integer_attribute(self, attribute: IntegerAttribute) -> Option<i32>;
fn get_unsigned_integer_attribute(self, attribute: UnsignedIntegerAttribute) -> Option<u32>; fn get_unsigned_integer_attribute(self, attribute: UnsignedIntegerAttribute) -> Option<u32>;
fn get_attr(self, namespace: &Namespace, attr: &Atom) -> Option<&'a str>; fn get_attr(self, namespace: &Namespace, attr: &Atom) -> Option<&'a str>;