/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ use crate::dom::attr::Attr; use crate::dom::bindings::codegen::Bindings::HTMLFontElementBinding; use crate::dom::bindings::codegen::Bindings::HTMLFontElementBinding::HTMLFontElementMethods; use crate::dom::bindings::inheritance::Castable; use crate::dom::bindings::root::{DomRoot, LayoutDom}; use crate::dom::bindings::str::DOMString; use crate::dom::document::Document; use crate::dom::element::{Element, RawLayoutElementHelpers}; use crate::dom::htmlelement::HTMLElement; use crate::dom::node::Node; use crate::dom::virtualmethods::VirtualMethods; use cssparser::RGBA; use dom_struct::dom_struct; use html5ever::{LocalName, Prefix}; use servo_atoms::Atom; use style::attr::AttrValue; use style::str::{read_numbers, HTML_SPACE_CHARACTERS}; #[dom_struct] pub struct HTMLFontElement { htmlelement: HTMLElement, } impl HTMLFontElement { fn new_inherited( local_name: LocalName, prefix: Option, document: &Document, ) -> HTMLFontElement { HTMLFontElement { htmlelement: HTMLElement::new_inherited(local_name, prefix, document), } } #[allow(unrooted_must_root)] pub fn new( local_name: LocalName, prefix: Option, document: &Document, ) -> DomRoot { Node::reflect_node( Box::new(HTMLFontElement::new_inherited(local_name, prefix, document)), document, HTMLFontElementBinding::Wrap, ) } } impl HTMLFontElementMethods for HTMLFontElement { // https://html.spec.whatwg.org/multipage/#dom-font-color make_getter!(Color, "color"); // https://html.spec.whatwg.org/multipage/#dom-font-color make_legacy_color_setter!(SetColor, "color"); // https://html.spec.whatwg.org/multipage/#dom-font-face make_getter!(Face, "face"); // https://html.spec.whatwg.org/multipage/#dom-font-face make_atomic_setter!(SetFace, "face"); // https://html.spec.whatwg.org/multipage/#dom-font-size make_getter!(Size, "size"); // https://html.spec.whatwg.org/multipage/#dom-font-size fn SetSize(&self, value: DOMString) { let element = self.upcast::(); element.set_attribute(&local_name!("size"), parse_size(&value)); } } impl VirtualMethods for HTMLFontElement { fn super_type(&self) -> Option<&dyn VirtualMethods> { Some(self.upcast::() as &dyn VirtualMethods) } fn attribute_affects_presentational_hints(&self, attr: &Attr) -> bool { if attr.local_name() == &local_name!("color") { return true; } // FIXME: Should also return true for `size` and `face` changes! self.super_type() .unwrap() .attribute_affects_presentational_hints(attr) } fn parse_plain_attribute(&self, name: &LocalName, value: DOMString) -> AttrValue { match name { &local_name!("face") => AttrValue::from_atomic(value.into()), &local_name!("color") => AttrValue::from_legacy_color(value.into()), &local_name!("size") => parse_size(&value), _ => self .super_type() .unwrap() .parse_plain_attribute(name, value), } } } pub trait HTMLFontElementLayoutHelpers { fn get_color(&self) -> Option; fn get_face(&self) -> Option; fn get_size(&self) -> Option; } impl HTMLFontElementLayoutHelpers for LayoutDom { #[allow(unsafe_code)] fn get_color(&self) -> Option { unsafe { (*self.upcast::().unsafe_get()) .get_attr_for_layout(&ns!(), &local_name!("color")) .and_then(AttrValue::as_color) .cloned() } } #[allow(unsafe_code)] fn get_face(&self) -> Option { unsafe { (*self.upcast::().unsafe_get()) .get_attr_for_layout(&ns!(), &local_name!("face")) .map(AttrValue::as_atom) .cloned() } } #[allow(unsafe_code)] fn get_size(&self) -> Option { let size = unsafe { (*self.upcast::().unsafe_get()) .get_attr_for_layout(&ns!(), &local_name!("size")) }; match size { Some(&AttrValue::UInt(_, s)) => Some(s), _ => None, } } } /// fn parse_size(mut input: &str) -> AttrValue { let original_input = input; // Steps 1 & 2 are not relevant // Step 3 input = input.trim_matches(HTML_SPACE_CHARACTERS); enum ParseMode { RelativePlus, RelativeMinus, Absolute, } let mut input_chars = input.chars().peekable(); let parse_mode = match input_chars.peek() { // Step 4 None => return AttrValue::String(original_input.into()), // Step 5 Some(&'+') => { let _ = input_chars.next(); // consume the '+' ParseMode::RelativePlus }, Some(&'-') => { let _ = input_chars.next(); // consume the '-' ParseMode::RelativeMinus }, Some(_) => ParseMode::Absolute, }; // Steps 6, 7, 8 let mut value = match read_numbers(input_chars) { (Some(v), _) if v >= 0 => v, _ => return AttrValue::String(original_input.into()), }; // Step 9 match parse_mode { ParseMode::RelativePlus => value = 3 + value, ParseMode::RelativeMinus => value = 3 - value, ParseMode::Absolute => (), } // Steps 10, 11, 12 AttrValue::UInt(original_input.into(), value as u32) }