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::CrossFade(..) |
41 Image::PaintWorklet(..) |
42 Image::None => None,
43 Image::LightDark(..) => unreachable!("light-dark() should be disabled"),
44 };
45
46 let content = match &marker_info.style.get_counters().content {
47 Content::Items(_) => generate_pseudo_element_content(&marker_info, context),
48 Content::None => return None,
49 Content::Normal => marker_image().or_else(|| {
50 Some(vec![PseudoElementContentItem::Text(marker_string(
51 &list_style.list_style_type,
52 )?)])
53 })?,
54 };
55
56 Some((marker_info, content))
57}
58
59fn symbol_to_string(symbol: &Symbol) -> &str {
60 match symbol {
61 Symbol::String(string) => string,
62 Symbol::Ident(ident) => &ident.0,
63 }
64}
65
66pub(crate) fn generate_counter_representation(counter_style: &CounterStyle) -> &str {
68 match counter_style {
71 CounterStyle::None | CounterStyle::String(_) => unreachable!("Invalid counter style"),
72 CounterStyle::Name(name) => match name.0 {
73 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",
80 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") |
98 atom!("cjk-earthly-branch") |
99 atom!("cjk-heavenly-stem") |
100 atom!("japanese-informal") => "\u{3007}", atom!("korean-hangul-formal") => "\u{C601}", atom!("korean-hanja-informal") |
103 atom!("korean-hanja-formal") |
104 atom!("japanese-formal") |
105 atom!("simp-chinese-informal") |
106 atom!("simp-chinese-formal") |
107 atom!("trad-chinese-informal") |
108 atom!("trad-chinese-formal") |
109 atom!("cjk-ideographic") => "\u{96F6}", _ => "0",
112 },
113 CounterStyle::Symbols { ty, symbols } => match ty {
114 SymbolsType::Numeric => {
116 symbol_to_string(symbols.0.first().expect("symbols() should have symbols"))
117 },
118 SymbolsType::Cyclic => {
121 symbol_to_string(symbols.0.last().expect("symbols() should have symbols"))
122 },
123 SymbolsType::Alphabetic | SymbolsType::Symbolic | SymbolsType::Fixed => "0",
126 },
127 }
128}
129
130pub(crate) fn marker_string(list_style_type: &ListStyleType) -> Option<String> {
132 let suffix = match &list_style_type.0 {
133 CounterStyle::None => return None,
134 CounterStyle::String(string) => return Some(string.to_string()),
135 CounterStyle::Name(name) => match name.0 {
136 atom!("disc") |
137 atom!("circle") |
138 atom!("square") |
139 atom!("disclosure-open") |
140 atom!("disclosure-closed") => " ",
141 atom!("hiragana") |
142 atom!("hiragana-iroha") |
143 atom!("katakana") |
144 atom!("katakana-iroha") |
145 atom!("cjk-decimal") |
146 atom!("cjk-earthly-branch") |
147 atom!("cjk-heavenly-stem") |
148 atom!("japanese-informal") |
149 atom!("japanese-formal") |
150 atom!("simp-chinese-informal") |
151 atom!("simp-chinese-formal") |
152 atom!("trad-chinese-informal") |
153 atom!("trad-chinese-formal") |
154 atom!("cjk-ideographic") => "\u{3001}", atom!("korean-hangul-formal") |
156 atom!("korean-hanja-informal") |
157 atom!("korean-hanja-formal") => ", ",
158 atom!("ethiopic-numeric") => "/ ",
159 _ => ". ",
160 },
161 CounterStyle::Symbols { .. } => " ",
162 };
163 Some(generate_counter_representation(&list_style_type.0).to_string() + suffix)
164}