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-height>
92    make_getter!(Height, "height");
93
94    // <https://html.spec.whatwg.org/multipage/#dom-tdth-height>
95    make_nonzero_dimension_setter!(SetHeight, "height");
96
97    // <https://html.spec.whatwg.org/multipage/#dom-tdth-width>
98    make_getter!(Width, "width");
99
100    // <https://html.spec.whatwg.org/multipage/#dom-tdth-width>
101    make_nonzero_dimension_setter!(SetWidth, "width");
102
103    // https://html.spec.whatwg.org/multipage/#dom-tdth-cellindex
104    fn CellIndex(&self) -> i32 {
105        let self_node = self.upcast::<Node>();
106
107        let parent_children = match self_node.GetParentNode() {
108            Some(ref parent_node) if parent_node.is::<HTMLTableRowElement>() => {
109                parent_node.children()
110            },
111            _ => return -1,
112        };
113
114        parent_children
115            .filter(|c| c.is::<HTMLTableCellElement>())
116            .position(|c| &*c == self_node)
117            .map_or(-1, |p| p as i32)
118    }
119}
120
121pub(crate) trait HTMLTableCellElementLayoutHelpers<'dom> {
122    fn get_background_color(self) -> Option<AbsoluteColor>;
123    fn get_colspan(self) -> Option<u32>;
124    fn get_rowspan(self) -> Option<u32>;
125    fn get_table(self) -> Option<LayoutDom<'dom, HTMLTableElement>>;
126    fn get_width(self) -> LengthOrPercentageOrAuto;
127    fn get_height(self) -> LengthOrPercentageOrAuto;
128}
129
130impl<'dom> HTMLTableCellElementLayoutHelpers<'dom> for LayoutDom<'dom, HTMLTableCellElement> {
131    fn get_background_color(self) -> Option<AbsoluteColor> {
132        self.upcast::<Element>()
133            .get_attr_for_layout(&ns!(), &local_name!("bgcolor"))
134            .and_then(AttrValue::as_color)
135            .cloned()
136    }
137
138    fn get_colspan(self) -> Option<u32> {
139        self.upcast::<Element>()
140            .get_attr_for_layout(&ns!(), &local_name!("colspan"))
141            .map(AttrValue::as_uint)
142    }
143
144    fn get_rowspan(self) -> Option<u32> {
145        self.upcast::<Element>()
146            .get_attr_for_layout(&ns!(), &local_name!("rowspan"))
147            .map(AttrValue::as_uint)
148    }
149
150    fn get_table(self) -> Option<LayoutDom<'dom, HTMLTableElement>> {
151        let row = self.upcast::<Node>().composed_parent_node_ref()?;
152        row.downcast::<HTMLTableRowElement>()?;
153        let section = row.composed_parent_node_ref()?;
154        section.downcast::<HTMLTableElement>().or_else(|| {
155            section.downcast::<HTMLTableSectionElement>()?;
156            let table = section.composed_parent_node_ref()?;
157            table.downcast::<HTMLTableElement>()
158        })
159    }
160
161    fn get_width(self) -> LengthOrPercentageOrAuto {
162        self.upcast::<Element>()
163            .get_attr_for_layout(&ns!(), &local_name!("width"))
164            .map(AttrValue::as_dimension)
165            .cloned()
166            .unwrap_or(LengthOrPercentageOrAuto::Auto)
167    }
168
169    fn get_height(self) -> LengthOrPercentageOrAuto {
170        self.upcast::<Element>()
171            .get_attr_for_layout(&ns!(), &local_name!("height"))
172            .map(AttrValue::as_dimension)
173            .cloned()
174            .unwrap_or(LengthOrPercentageOrAuto::Auto)
175    }
176}
177
178impl VirtualMethods for HTMLTableCellElement {
179    fn super_type(&self) -> Option<&dyn VirtualMethods> {
180        Some(self.upcast::<HTMLElement>() as &dyn VirtualMethods)
181    }
182
183    fn attribute_mutated(&self, attr: &Attr, mutation: AttributeMutation, can_gc: CanGc) {
184        if let Some(super_type) = self.super_type() {
185            super_type.attribute_mutated(attr, mutation, can_gc);
186        }
187
188        if matches!(*attr.local_name(), local_name!("colspan")) {
189            self.upcast::<Node>().dirty(NodeDamage::Other);
190        }
191        if matches!(*attr.local_name(), local_name!("rowspan")) {
192            self.upcast::<Node>().dirty(NodeDamage::Other);
193        }
194    }
195
196    fn attribute_affects_presentational_hints(&self, attr: &Attr) -> bool {
197        match attr.local_name() {
198            &local_name!("width") | &local_name!("height") => true,
199            _ => self
200                .super_type()
201                .unwrap()
202                .attribute_affects_presentational_hints(attr),
203        }
204    }
205
206    fn parse_plain_attribute(&self, local_name: &LocalName, value: DOMString) -> AttrValue {
207        match *local_name {
208            local_name!("colspan") => {
209                let mut attr = AttrValue::from_u32(value.into(), DEFAULT_COLSPAN);
210                if let AttrValue::UInt(_, ref mut value) = attr {
211                    // From <https://html.spec.whatwg.org/multipage/#dom-tdth-colspan>:
212                    // > The colSpan IDL attribute must reflect the colspan content attribute. It is clamped to
213                    // > the range [1, 1000], and its default value is 1.
214                    *value = (*value).clamp(1, 1000);
215                }
216                attr
217            },
218            local_name!("rowspan") => {
219                let mut attr = AttrValue::from_u32(value.into(), DEFAULT_ROWSPAN);
220                if let AttrValue::UInt(_, ref mut value) = attr {
221                    // From <https://html.spec.whatwg.org/multipage/#dom-tdth-rowspan>:
222                    // > The rowSpan IDL attribute must reflect the rowspan content attribute. It is clamped to
223                    // > the range [0, 65534], and its default value is 1.
224                    // Note Firefox floors by 1 in quirks mode, but like Chrome and Safari we don't do that.
225                    *value = (*value).clamp(0, 65534);
226                }
227                attr
228            },
229            local_name!("bgcolor") => AttrValue::from_legacy_color(value.into()),
230            local_name!("width") => AttrValue::from_nonzero_dimension(value.into()),
231            local_name!("height") => AttrValue::from_nonzero_dimension(value.into()),
232            _ => self
233                .super_type()
234                .unwrap()
235                .parse_plain_attribute(local_name, value),
236        }
237    }
238}