script/dom/html/
htmltablecellelement.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5use dom_struct::dom_struct;
6use html5ever::{LocalName, Prefix, local_name, ns};
7use js::rust::HandleObject;
8use style::attr::{AttrValue, LengthOrPercentageOrAuto};
9use style::color::AbsoluteColor;
10
11use crate::dom::attr::Attr;
12use crate::dom::bindings::codegen::Bindings::HTMLTableCellElementBinding::HTMLTableCellElementMethods;
13use crate::dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
14use crate::dom::bindings::inheritance::Castable;
15use crate::dom::bindings::root::{DomRoot, LayoutDom};
16use crate::dom::bindings::str::DOMString;
17use crate::dom::document::Document;
18use crate::dom::element::{AttributeMutation, Element, LayoutElementHelpers};
19use crate::dom::html::htmlelement::HTMLElement;
20use crate::dom::html::htmltableelement::HTMLTableElement;
21use crate::dom::html::htmltablerowelement::HTMLTableRowElement;
22use crate::dom::html::htmltablesectionelement::HTMLTableSectionElement;
23use crate::dom::node::{LayoutNodeHelpers, Node, NodeDamage};
24use crate::dom::virtualmethods::VirtualMethods;
25use crate::script_runtime::CanGc;
26
27const DEFAULT_COLSPAN: u32 = 1;
28const DEFAULT_ROWSPAN: u32 = 1;
29
30#[dom_struct]
31pub(crate) struct HTMLTableCellElement {
32    htmlelement: HTMLElement,
33}
34
35impl HTMLTableCellElement {
36    fn new_inherited(
37        local_name: LocalName,
38        prefix: Option<Prefix>,
39        document: &Document,
40    ) -> HTMLTableCellElement {
41        HTMLTableCellElement {
42            htmlelement: HTMLElement::new_inherited(local_name, prefix, document),
43        }
44    }
45
46    #[cfg_attr(crown, allow(crown::unrooted_must_root))]
47    pub(crate) fn new(
48        local_name: LocalName,
49        prefix: Option<Prefix>,
50        document: &Document,
51        proto: Option<HandleObject>,
52        can_gc: CanGc,
53    ) -> DomRoot<HTMLTableCellElement> {
54        let n = Node::reflect_node_with_proto(
55            Box::new(HTMLTableCellElement::new_inherited(
56                local_name, prefix, document,
57            )),
58            document,
59            proto,
60            can_gc,
61        );
62
63        n.upcast::<Node>().set_weird_parser_insertion_mode();
64        n
65    }
66}
67
68impl HTMLTableCellElementMethods<crate::DomTypeHolder> for HTMLTableCellElement {
69    // https://html.spec.whatwg.org/multipage/#dom-tdth-colspan
70    make_uint_getter!(ColSpan, "colspan", DEFAULT_COLSPAN);
71
72    // https://html.spec.whatwg.org/multipage/#dom-tdth-colspan
73    // > The colSpan IDL attribute must reflect the colspan content attribute. It is clamped to
74    // > the range [1, 1000], and its default value is 1.
75    make_clamped_uint_setter!(SetColSpan, "colspan", 1, 1000, 1);
76
77    // https://html.spec.whatwg.org/multipage/#dom-tdth-rowspan
78    make_uint_getter!(RowSpan, "rowspan", DEFAULT_ROWSPAN);
79
80    // https://html.spec.whatwg.org/multipage/#dom-tdth-rowspan
81    // > The rowSpan IDL attribute must reflect the rowspan content attribute. It is clamped to
82    // > the range [0, 65534], and its default value is 1.
83    make_clamped_uint_setter!(SetRowSpan, "rowspan", 0, 65534, 1);
84
85    // https://html.spec.whatwg.org/multipage/#dom-tdth-bgcolor
86    make_getter!(BgColor, "bgcolor");
87
88    // https://html.spec.whatwg.org/multipage/#dom-tdth-bgcolor
89    make_legacy_color_setter!(SetBgColor, "bgcolor");
90
91    // https://html.spec.whatwg.org/multipage/#dom-tdth-width
92    make_getter!(Width, "width");
93
94    // https://html.spec.whatwg.org/multipage/#dom-tdth-width
95    make_nonzero_dimension_setter!(SetWidth, "width");
96
97    // https://html.spec.whatwg.org/multipage/#dom-tdth-cellindex
98    fn CellIndex(&self) -> i32 {
99        let self_node = self.upcast::<Node>();
100
101        let parent_children = match self_node.GetParentNode() {
102            Some(ref parent_node) if parent_node.is::<HTMLTableRowElement>() => {
103                parent_node.children()
104            },
105            _ => return -1,
106        };
107
108        parent_children
109            .filter(|c| c.is::<HTMLTableCellElement>())
110            .position(|c| &*c == self_node)
111            .map_or(-1, |p| p as i32)
112    }
113}
114
115pub(crate) trait HTMLTableCellElementLayoutHelpers<'dom> {
116    fn get_background_color(self) -> Option<AbsoluteColor>;
117    fn get_colspan(self) -> Option<u32>;
118    fn get_rowspan(self) -> Option<u32>;
119    fn get_table(self) -> Option<LayoutDom<'dom, HTMLTableElement>>;
120    fn get_width(self) -> LengthOrPercentageOrAuto;
121    fn get_height(self) -> LengthOrPercentageOrAuto;
122}
123
124impl<'dom> HTMLTableCellElementLayoutHelpers<'dom> for LayoutDom<'dom, HTMLTableCellElement> {
125    fn get_background_color(self) -> Option<AbsoluteColor> {
126        self.upcast::<Element>()
127            .get_attr_for_layout(&ns!(), &local_name!("bgcolor"))
128            .and_then(AttrValue::as_color)
129            .cloned()
130    }
131
132    fn get_colspan(self) -> Option<u32> {
133        self.upcast::<Element>()
134            .get_attr_for_layout(&ns!(), &local_name!("colspan"))
135            .map(AttrValue::as_uint)
136    }
137
138    fn get_rowspan(self) -> Option<u32> {
139        self.upcast::<Element>()
140            .get_attr_for_layout(&ns!(), &local_name!("rowspan"))
141            .map(AttrValue::as_uint)
142    }
143
144    fn get_table(self) -> Option<LayoutDom<'dom, HTMLTableElement>> {
145        let row = self.upcast::<Node>().composed_parent_node_ref()?;
146        row.downcast::<HTMLTableRowElement>()?;
147        let section = row.composed_parent_node_ref()?;
148        section.downcast::<HTMLTableElement>().or_else(|| {
149            section.downcast::<HTMLTableSectionElement>()?;
150            let table = section.composed_parent_node_ref()?;
151            table.downcast::<HTMLTableElement>()
152        })
153    }
154
155    fn get_width(self) -> LengthOrPercentageOrAuto {
156        self.upcast::<Element>()
157            .get_attr_for_layout(&ns!(), &local_name!("width"))
158            .map(AttrValue::as_dimension)
159            .cloned()
160            .unwrap_or(LengthOrPercentageOrAuto::Auto)
161    }
162
163    fn get_height(self) -> LengthOrPercentageOrAuto {
164        self.upcast::<Element>()
165            .get_attr_for_layout(&ns!(), &local_name!("height"))
166            .map(AttrValue::as_dimension)
167            .cloned()
168            .unwrap_or(LengthOrPercentageOrAuto::Auto)
169    }
170}
171
172impl VirtualMethods for HTMLTableCellElement {
173    fn super_type(&self) -> Option<&dyn VirtualMethods> {
174        Some(self.upcast::<HTMLElement>() as &dyn VirtualMethods)
175    }
176
177    fn attribute_mutated(&self, attr: &Attr, mutation: AttributeMutation, can_gc: CanGc) {
178        if let Some(super_type) = self.super_type() {
179            super_type.attribute_mutated(attr, mutation, can_gc);
180        }
181
182        if matches!(*attr.local_name(), local_name!("colspan")) {
183            self.upcast::<Node>().dirty(NodeDamage::Other);
184        }
185        if matches!(*attr.local_name(), local_name!("rowspan")) {
186            self.upcast::<Node>().dirty(NodeDamage::Other);
187        }
188    }
189
190    fn parse_plain_attribute(&self, local_name: &LocalName, value: DOMString) -> AttrValue {
191        match *local_name {
192            local_name!("colspan") => {
193                let mut attr = AttrValue::from_u32(value.into(), DEFAULT_COLSPAN);
194                if let AttrValue::UInt(_, ref mut value) = attr {
195                    // From <https://html.spec.whatwg.org/multipage/#dom-tdth-colspan>:
196                    // > The colSpan IDL attribute must reflect the colspan content attribute. It is clamped to
197                    // > the range [1, 1000], and its default value is 1.
198                    *value = (*value).clamp(1, 1000);
199                }
200                attr
201            },
202            local_name!("rowspan") => {
203                let mut attr = AttrValue::from_u32(value.into(), DEFAULT_ROWSPAN);
204                if let AttrValue::UInt(_, ref mut value) = attr {
205                    // From <https://html.spec.whatwg.org/multipage/#dom-tdth-rowspan>:
206                    // > The rowSpan IDL attribute must reflect the rowspan content attribute. It is clamped to
207                    // > the range [0, 65534], and its default value is 1.
208                    // Note Firefox floors by 1 in quirks mode, but like Chrome and Safari we don't do that.
209                    *value = (*value).clamp(0, 65534);
210                }
211                attr
212            },
213            local_name!("bgcolor") => AttrValue::from_legacy_color(value.into()),
214            local_name!("width") => AttrValue::from_nonzero_dimension(value.into()),
215            local_name!("height") => AttrValue::from_nonzero_dimension(value.into()),
216            _ => self
217                .super_type()
218                .unwrap()
219                .parse_plain_attribute(local_name, value),
220        }
221    }
222}