1use style::counter_style::{CounterStyle, Symbol, SymbolsType};
6use style::properties::longhands::list_style_type::computed_value::T as ListStyleType;
7use style::values::computed::Image;
8use style::values::generics::counters::Content;
9use stylo_atoms::atom;
10
11use crate::context::LayoutContext;
12use crate::dom_traversal::{
13 NodeAndStyleInfo, PseudoElementContentItem, generate_pseudo_element_content,
14};
15use crate::replaced::ReplacedContents;
16
17pub(crate) fn make_marker<'dom>(
19 context: &LayoutContext,
20 info: &NodeAndStyleInfo<'dom>,
21) -> Option<(NodeAndStyleInfo<'dom>, Vec<PseudoElementContentItem>)> {
22 let marker_info =
23 info.with_pseudo_element(context, style::selector_parser::PseudoElement::Marker)?;
24 let style = &marker_info.style;
25 let list_style = style.get_list();
26
27 let marker_image = || match &list_style.list_style_image {
29 Image::Url(url) => Some(vec![
30 PseudoElementContentItem::Replaced(ReplacedContents::from_image_url(
31 marker_info.node,
32 context,
33 url,
34 )?),
35 PseudoElementContentItem::Text(" ".into()),
36 ]),
37 Image::ImageSet(..) |
39 Image::Gradient(..) |
40 Image::Image(..) |
41 Image::CrossFade(..) |
42 Image::PaintWorklet(..) |
43 Image::None => None,
44 Image::LightDark(..) => unreachable!("light-dark() should be disabled"),
45 };
46
47 let content = match &marker_info.style.get_counters().content {
48 Content::Items(_) => generate_pseudo_element_content(&marker_info, context),
49 Content::None => return None,
50 Content::Normal => marker_image().or_else(|| {
51 Some(vec![PseudoElementContentItem::Text(marker_string(
52 &list_style.list_style_type,
53 )?)])
54 })?,
55 };
56
57 Some((marker_info, content))
58}
59
60fn symbol_to_string(symbol: &Symbol) -> &str {
61 match symbol {
62 Symbol::String(string) => string,
63 Symbol::Ident(ident) => &ident.0,
64 }
65}
66
67pub(crate) fn generate_counter_representation(counter_style: &CounterStyle) -> &str {
69 match counter_style {
72 CounterStyle::None | CounterStyle::String(_) => unreachable!("Invalid counter style"),
73 CounterStyle::Name(name) => match name.0 {
74 atom!("disc") => "\u{2022}", atom!("circle") => "\u{25E6}", atom!("square") => "\u{25AA}", atom!("disclosure-open") => "\u{25BE}", atom!("disclosure-closed") => "\u{25B8}", atom!("decimal-leading-zero") => "00",
81 atom!("arabic-indic") => "\u{660}", atom!("bengali") => "\u{9E6}", atom!("cambodian") | atom!("khmer") => "\u{17E0}", atom!("devanagari") => "\u{966}", atom!("gujarati") => "\u{AE6}", atom!("gurmukhi") => "\u{A66}", atom!("kannada") => "\u{CE6}", atom!("lao") => "\u{ED0}", atom!("malayalam") => "\u{D66}", atom!("mongolian") => "\u{1810}", atom!("myanmar") => "\u{1040}", atom!("oriya") => "\u{B66}", atom!("persian") => "\u{6F0}", atom!("tamil") => "\u{BE6}", atom!("telugu") => "\u{C66}", atom!("thai") => "\u{E50}", atom!("tibetan") => "\u{F20}", atom!("cjk-decimal") |
99 atom!("cjk-earthly-branch") |
100 atom!("cjk-heavenly-stem") |
101 atom!("japanese-informal") => "\u{3007}", atom!("korean-hangul-formal") => "\u{C601}", atom!("korean-hanja-informal") |
104 atom!("korean-hanja-formal") |
105 atom!("japanese-formal") |
106 atom!("simp-chinese-informal") |
107 atom!("simp-chinese-formal") |
108 atom!("trad-chinese-informal") |
109 atom!("trad-chinese-formal") |
110 atom!("cjk-ideographic") => "\u{96F6}", _ => "0",
113 },
114 CounterStyle::Symbols { ty, symbols } => match ty {
115 SymbolsType::Numeric => {
117 symbol_to_string(symbols.0.first().expect("symbols() should have symbols"))
118 },
119 SymbolsType::Cyclic => {
122 symbol_to_string(symbols.0.last().expect("symbols() should have symbols"))
123 },
124 SymbolsType::Alphabetic | SymbolsType::Symbolic | SymbolsType::Fixed => "0",
127 },
128 }
129}
130
131pub(crate) fn marker_string(list_style_type: &ListStyleType) -> Option<String> {
133 let suffix = match &list_style_type.0 {
134 CounterStyle::None => return None,
135 CounterStyle::String(string) => return Some(string.to_string()),
136 CounterStyle::Name(name) => match name.0 {
137 atom!("disc") |
138 atom!("circle") |
139 atom!("square") |
140 atom!("disclosure-open") |
141 atom!("disclosure-closed") => " ",
142 atom!("hiragana") |
143 atom!("hiragana-iroha") |
144 atom!("katakana") |
145 atom!("katakana-iroha") |
146 atom!("cjk-decimal") |
147 atom!("cjk-earthly-branch") |
148 atom!("cjk-heavenly-stem") |
149 atom!("japanese-informal") |
150 atom!("japanese-formal") |
151 atom!("simp-chinese-informal") |
152 atom!("simp-chinese-formal") |
153 atom!("trad-chinese-informal") |
154 atom!("trad-chinese-formal") |
155 atom!("cjk-ideographic") => "\u{3001}", atom!("korean-hangul-formal") |
157 atom!("korean-hanja-informal") |
158 atom!("korean-hanja-formal") => ", ",
159 atom!("ethiopic-numeric") => "/ ",
160 _ => ". ",
161 },
162 CounterStyle::Symbols { .. } => " ",
163 };
164 Some(generate_counter_representation(&list_style_type.0).to_string() + suffix)
165}