layout: Introduce support for legacy presentational attributes to selector

matching, and use it for `<input size>` and `<td width>`.

This implements a general framework for legacy presentational attributes
to the DOM and style calculation, so that adding more of them later will
be straightforward.
This commit is contained in:
Patrick Walton 2014-10-14 11:25:29 -07:00
parent 8077edc062
commit 5f8d3f72d8
31 changed files with 570 additions and 214 deletions

View file

@ -53,6 +53,7 @@ use script_traits::UntrustedNodeAddress;
use servo_msg::compositor_msg::ScriptListener;
use servo_msg::constellation_msg::ConstellationChan;
use servo_util::smallvec::{SmallVec1, SmallVec};
use servo_util::str::LengthOrPercentageOrAuto;
use layout_interface::{LayoutRPC, LayoutChan};
use dom::bindings::utils::WindowProxyHandler;
@ -234,3 +235,6 @@ impl JSTraceable for Box<LayoutRPC+'static> {
// Do nothing
}
}
untraceable!(LengthOrPercentageOrAuto)

View file

@ -11,7 +11,8 @@ use dom::bindings::codegen::Bindings::AttrBinding::AttrMethods;
use dom::bindings::codegen::Bindings::ElementBinding;
use dom::bindings::codegen::Bindings::ElementBinding::ElementMethods;
use dom::bindings::codegen::Bindings::NamedNodeMapBinding::NamedNodeMapMethods;
use dom::bindings::codegen::InheritTypes::{ElementDerived, NodeCast};
use dom::bindings::codegen::InheritTypes::{ElementDerived, HTMLInputElementDerived};
use dom::bindings::codegen::InheritTypes::{HTMLTableCellElementDerived, NodeCast};
use dom::bindings::js::{MutNullableJS, JS, JSRef, Temporary, TemporaryPushable};
use dom::bindings::js::{OptionalSettable, OptionalRootable, Root};
use dom::bindings::utils::{Reflectable, Reflector};
@ -23,16 +24,19 @@ use dom::document::{Document, DocumentHelpers};
use dom::domtokenlist::DOMTokenList;
use dom::eventtarget::{EventTarget, NodeTargetTypeId};
use dom::htmlcollection::HTMLCollection;
use dom::htmlinputelement::{HTMLInputElement, LayoutHTMLInputElementHelpers};
use dom::htmlserializer::serialize;
use dom::htmltablecellelement::{HTMLTableCellElement, HTMLTableCellElementHelpers};
use dom::node::{ElementNodeTypeId, Node, NodeHelpers, NodeIterator, document_from_node};
use dom::node::{window_from_node, LayoutNodeHelpers};
use dom::nodelist::NodeList;
use dom::virtualmethods::{VirtualMethods, vtable_for};
use devtools_traits::AttrInfo;
use style::{IntegerAttribute, LengthAttribute, SizeIntegerAttribute, WidthLengthAttribute};
use style::{matches, parse_selector_list_from_str};
use style;
use servo_util::namespace;
use servo_util::str::DOMString;
use servo_util::str::{DOMString, LengthOrPercentageOrAuto};
use std::ascii::StrAsciiExt;
use std::cell::{Ref, RefMut, RefCell};
@ -211,6 +215,10 @@ pub trait RawLayoutElementHelpers {
unsafe fn get_attr_atom_for_layout(&self, namespace: &Namespace, name: &Atom) -> Option<Atom>;
unsafe fn has_class_for_layout(&self, name: &Atom) -> bool;
unsafe fn get_classes_for_layout(&self) -> Option<&'static [Atom]>;
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>;
}
impl RawLayoutElementHelpers for Element {
@ -288,6 +296,36 @@ impl RawLayoutElementHelpers for Element {
(*attr).value_tokens_forever()
})
}
#[inline]
#[allow(unrooted_must_root)]
unsafe fn get_length_attribute_for_layout(&self, length_attribute: LengthAttribute)
-> LengthOrPercentageOrAuto {
match length_attribute {
WidthLengthAttribute => {
if !self.is_htmltablecellelement() {
fail!("I'm not a table cell!")
}
let this: &HTMLTableCellElement = mem::transmute(self);
this.get_width()
}
}
}
#[inline]
#[allow(unrooted_must_root)]
unsafe fn get_integer_attribute_for_layout(&self, integer_attribute: IntegerAttribute)
-> Option<i32> {
match integer_attribute {
SizeIntegerAttribute => {
if !self.is_htmlinputelement() {
fail!("I'm not a form input!")
}
let this: &HTMLInputElement = mem::transmute(self);
Some(this.get_size_for_layout() as i32)
}
}
}
}
pub trait LayoutElementHelpers {
@ -1133,3 +1171,4 @@ impl<'a> style::TElement<'a> for JSRef<'a, Element> {
}
}
}

View file

@ -88,14 +88,14 @@ pub trait LayoutHTMLInputElementHelpers {
unsafe fn get_size_for_layout(&self) -> u32;
}
impl LayoutHTMLInputElementHelpers for JS<HTMLInputElement> {
impl LayoutHTMLInputElementHelpers for HTMLInputElement {
#[allow(unrooted_must_root)]
unsafe fn get_value_for_layout(&self) -> String {
unsafe fn get_raw_value(input: &JS<HTMLInputElement>) -> Option<String> {
mem::transmute::<&RefCell<Option<String>>, &Option<String>>(&(*input.unsafe_get()).value).clone()
unsafe fn get_raw_value(input: &HTMLInputElement) -> Option<String> {
mem::transmute::<&RefCell<Option<String>>, &Option<String>>(&input.value).clone()
}
match (*self.unsafe_get()).input_type.get() {
match self.input_type.get() {
InputCheckbox | InputRadio => "".to_string(),
InputFile | InputImage => "".to_string(),
InputButton(ref default) => get_raw_value(self)
@ -111,7 +111,17 @@ impl LayoutHTMLInputElementHelpers for JS<HTMLInputElement> {
#[allow(unrooted_must_root)]
unsafe fn get_size_for_layout(&self) -> u32 {
(*self.unsafe_get()).size.get()
self.size.get()
}
}
impl LayoutHTMLInputElementHelpers for JS<HTMLInputElement> {
unsafe fn get_value_for_layout(&self) -> String {
(*self.unsafe_get()).get_value_for_layout()
}
unsafe fn get_size_for_layout(&self) -> u32 {
(*self.unsafe_get()).get_size_for_layout()
}
}
@ -187,11 +197,12 @@ impl<'a> HTMLInputElementMethods for JSRef<'a, HTMLInputElement> {
make_setter!(SetFormTarget, "formtarget")
}
trait HTMLInputElementHelpers {
pub trait HTMLInputElementHelpers {
fn force_relayout(self);
fn radio_group_updated(self, group: Option<&str>);
fn get_radio_group(self) -> Option<String>;
fn update_checked_state(self, checked: bool);
fn get_size(&self) -> u32;
}
fn broadcast_radio_checked(broadcaster: JSRef<HTMLInputElement>, group: Option<&str>) {
@ -248,6 +259,10 @@ impl<'a> HTMLInputElementHelpers for JSRef<'a, HTMLInputElement> {
//TODO: dispatch change event
self.force_relayout();
}
fn get_size(&self) -> u32 {
self.size.get()
}
}
impl<'a> VirtualMethods for JSRef<'a, HTMLInputElement> {

View file

@ -2,21 +2,28 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use dom::bindings::codegen::InheritTypes::HTMLTableCellElementDerived;
use dom::bindings::codegen::InheritTypes::{HTMLElementCast, HTMLTableCellElementDerived};
use dom::bindings::js::JSRef;
use dom::bindings::utils::{Reflectable, Reflector};
use dom::document::Document;
use dom::element::{ElementTypeId, HTMLTableDataCellElementTypeId, HTMLTableHeaderCellElementTypeId};
use dom::element::{ElementTypeId, HTMLTableDataCellElementTypeId};
use dom::element::{HTMLTableHeaderCellElementTypeId};
use dom::eventtarget::{EventTarget, NodeTargetTypeId};
use dom::htmlelement::HTMLElement;
use dom::node::ElementNodeTypeId;
use servo_util::str::DOMString;
use dom::virtualmethods::VirtualMethods;
use servo_util::str::{AutoLpa, DOMString, LengthOrPercentageOrAuto};
use servo_util::str;
use std::cell::Cell;
use string_cache::Atom;
#[jstraceable]
#[must_root]
#[privatize]
pub struct HTMLTableCellElement {
htmlelement: HTMLElement,
width: Cell<LengthOrPercentageOrAuto>,
}
impl HTMLTableCellElementDerived for EventTarget {
@ -32,16 +39,58 @@ impl HTMLTableCellElementDerived for EventTarget {
impl HTMLTableCellElement {
pub fn new_inherited(type_id: ElementTypeId, tag_name: DOMString, prefix: Option<DOMString>, document: JSRef<Document>) -> HTMLTableCellElement {
HTMLTableCellElement {
htmlelement: HTMLElement::new_inherited(type_id, tag_name, prefix, document)
htmlelement: HTMLElement::new_inherited(type_id, tag_name, prefix, document),
width: Cell::new(AutoLpa)
}
}
#[inline]
pub fn htmlelement<'a>(&'a self) -> &'a HTMLElement {
pub fn htmlelement(&self) -> &HTMLElement {
&self.htmlelement
}
}
pub trait HTMLTableCellElementHelpers {
fn get_width(&self) -> LengthOrPercentageOrAuto;
}
impl HTMLTableCellElementHelpers for HTMLTableCellElement {
fn get_width(&self) -> LengthOrPercentageOrAuto {
self.width.get()
}
}
impl<'a> VirtualMethods for JSRef<'a, HTMLTableCellElement> {
fn super_type<'a>(&'a self) -> Option<&'a VirtualMethods> {
let htmlelement: &JSRef<HTMLElement> = HTMLElementCast::from_borrowed_ref(self);
Some(htmlelement as &VirtualMethods)
}
fn after_set_attr(&self, name: &Atom, value: DOMString) {
match self.super_type() {
Some(ref s) => s.after_set_attr(name, value.clone()),
_ => {}
}
match name.as_slice() {
"width" => self.width.set(str::parse_length(value.as_slice())),
_ => {}
}
}
fn before_remove_attr(&self, name: &Atom, value: DOMString) {
match self.super_type() {
Some(ref s) => s.before_remove_attr(name, value),
_ => {}
}
match name.as_slice() {
"width" => self.width.set(AutoLpa),
_ => {}
}
}
}
impl Reflectable for HTMLTableCellElement {
fn reflector<'a>(&'a self) -> &'a Reflector {
self.htmlelement.reflector()

View file

@ -19,6 +19,7 @@ use dom::bindings::codegen::InheritTypes::HTMLOptGroupElementCast;
use dom::bindings::codegen::InheritTypes::HTMLOptionElementCast;
use dom::bindings::codegen::InheritTypes::HTMLSelectElementCast;
use dom::bindings::codegen::InheritTypes::HTMLStyleElementCast;
use dom::bindings::codegen::InheritTypes::HTMLTableCellElementCast;
use dom::bindings::codegen::InheritTypes::HTMLTextAreaElementCast;
use dom::bindings::js::JSRef;
use dom::element::Element;
@ -37,6 +38,8 @@ use dom::element::HTMLOptGroupElementTypeId;
use dom::element::HTMLOptionElementTypeId;
use dom::element::HTMLSelectElementTypeId;
use dom::element::HTMLStyleElementTypeId;
use dom::element::HTMLTableDataCellElementTypeId;
use dom::element::HTMLTableHeaderCellElementTypeId;
use dom::element::HTMLTextAreaElementTypeId;
use dom::event::Event;
use dom::htmlanchorelement::HTMLAnchorElement;
@ -54,6 +57,7 @@ use dom::htmloptgroupelement::HTMLOptGroupElement;
use dom::htmloptionelement::HTMLOptionElement;
use dom::htmlselectelement::HTMLSelectElement;
use dom::htmlstyleelement::HTMLStyleElement;
use dom::htmltablecellelement::HTMLTableCellElement;
use dom::htmltextareaelement::HTMLTextAreaElement;
use dom::node::{Node, NodeHelpers, ElementNodeTypeId};
@ -193,6 +197,11 @@ pub fn vtable_for<'a>(node: &'a JSRef<'a, Node>) -> &'a VirtualMethods + 'a {
let element: &'a JSRef<'a, HTMLStyleElement> = HTMLStyleElementCast::to_borrowed_ref(node).unwrap();
element as &'a VirtualMethods + 'a
}
ElementNodeTypeId(HTMLTableDataCellElementTypeId) |
ElementNodeTypeId(HTMLTableHeaderCellElementTypeId) => {
let element: &'a JSRef<'a, HTMLTableCellElement> = HTMLTableCellElementCast::to_borrowed_ref(node).unwrap();
element as &'a VirtualMethods + 'a
}
ElementNodeTypeId(HTMLTextAreaElementTypeId) => {
let element: &'a JSRef<'a, HTMLTextAreaElement> = HTMLTextAreaElementCast::to_borrowed_ref(node).unwrap();
element as &'a VirtualMethods + 'a