script/dom/execcommand/commands/
fontsize.rs1use app_units::Au;
6use js::context::JSContext;
7use servo_config::pref;
8use style::attr::parse_integer;
9use style::values::computed::CSSPixelLength;
10use style::values::specified::FontSize;
11
12use crate::dom::bindings::codegen::Bindings::DocumentBinding::DocumentMethods;
13use crate::dom::bindings::str::DOMString;
14use crate::dom::document::Document;
15use crate::dom::execcommand::basecommand::CommandName;
16use crate::dom::selection::Selection;
17
18pub(crate) fn legacy_font_size_for(pixel_size: f32, document: &Document) -> DOMString {
20 let quirks_mode = document.quirks_mode();
21 let base_size = CSSPixelLength::from(Au::from_f32_px(pref!(fonts_default_size) as f32));
22 let mut returned_size = 1;
24 while returned_size < 7 {
26 let FontSize::Keyword(lower_keyword) = FontSize::from_html_size(returned_size) else {
29 unreachable!("Always computed as keyword");
30 };
31 let lower_bound = lower_keyword
32 .kw
33 .to_length_without_context(quirks_mode, base_size);
34 let FontSize::Keyword(upper_keyword) = FontSize::from_html_size(returned_size + 1) else {
37 unreachable!("Always computed as keyword");
38 };
39 let upper_bound = upper_keyword
40 .kw
41 .to_length_without_context(quirks_mode, base_size);
42 let average = (lower_bound.0.px() + upper_bound.0.px()) / 2.0;
44 if pixel_size < average {
49 break;
50 }
51 returned_size += 1;
53 }
54 returned_size.to_string().into()
56}
57
58enum ParsingMode {
59 RelativePlus,
60 RelativeMinus,
61 Absolute,
62}
63
64pub(crate) fn execute_fontsize_command(
66 cx: &mut JSContext,
67 document: &Document,
68 selection: &Selection,
69 value: DOMString,
70) -> bool {
71 let value = {
73 let mut value = value;
74 value.strip_leading_and_trailing_ascii_whitespace();
75 value
76 };
77 if !value.is_valid_floating_point_number_string() {
82 return false;
83 }
84 let (value, mode) = if value.starts_with('+') {
87 let stripped_plus = &value.str()[1..];
88 if !DOMString::from(stripped_plus).is_valid_floating_point_number_string() {
90 return false;
91 }
92 (stripped_plus.to_owned(), ParsingMode::RelativePlus)
93 } else if value.starts_with('-') {
94 (value.str()[1..].to_owned(), ParsingMode::RelativeMinus)
97 } else {
98 (value.into(), ParsingMode::Absolute)
100 };
101 let number = parse_integer(value.chars()).expect("Already validated floating number before");
103 let number = match mode {
104 ParsingMode::RelativePlus => number + 3,
106 ParsingMode::RelativeMinus => (-number) + 3,
108 ParsingMode::Absolute => number,
109 };
110 let number = number.clamp(1, 7) as u32;
113 let value = font_size_to_css_font(&number);
115 selection.set_the_selection_value(cx, Some(value.into()), CommandName::FontSize, document);
117 true
119}
120
121pub(crate) fn value_for_fontsize_command(
123 cx: &mut JSContext,
124 document: &Document,
125) -> Option<DOMString> {
126 let selection = document.GetSelection(cx)?;
128 let active_range = selection.active_range()?;
129 let command_value = active_range
134 .first_formattable_contained_node()
135 .unwrap_or_else(|| active_range.start_container())
136 .effective_command_value(&CommandName::FontSize)?;
137 maybe_normalize_pixels(&command_value, document)
139}
140
141pub(crate) fn maybe_normalize_pixels(
146 command_value: &DOMString,
147 document: &Document,
148) -> Option<DOMString> {
149 if command_value.ends_with_str("px") {
150 command_value.str()[0..command_value.len() - 2]
151 .parse::<f32>()
152 .ok()
153 .map(|value| legacy_font_size_for(value, document))
154 } else {
155 Some(css_font_to_font_size(&command_value.str()).into())
156 }
157}
158
159fn css_font_to_font_size(str_: &str) -> &str {
160 match str_ {
161 "x-small" => "1",
162 "small" => "2",
163 "medium" => "3",
164 "large" => "4",
165 "x-large" => "5",
166 "xx-large" => "6",
167 "xxx-large" => "7",
168 _ => str_,
169 }
170}
171
172pub(crate) fn font_size_to_css_font(value: &u32) -> &str {
173 match value {
174 1 => "x-small",
175 2 => "small",
176 3 => "medium",
177 4 => "large",
178 5 => "x-large",
179 6 => "xx-large",
180 7 => "xxx-large",
181 _ => unreachable!(),
182 }
183}
184
185pub(crate) fn font_size_loosely_equivalent(first: &DOMString, second: &DOMString) -> bool {
188 css_font_to_font_size(&first.str()) == second || first == css_font_to_font_size(&second.str())
192}