1use std::borrow::Borrow;
34use std::fmt;
35
36use cssparser::{ToCss, serialize_identifier};
37use precomputed_hash::PrecomputedHash;
38use selectors::attr::{AttrSelectorOperation, CaseSensitivity, NamespaceConstraint};
39use selectors::bloom::{BLOOM_HASH_MASK, BloomFilter};
40use selectors::matching::{ElementSelectorFlags, MatchingContext};
41use selectors::parser::{NonTSPseudoClass, PseudoElement as PseudoElementTrait, SelectorImpl};
42use selectors::{Element, OpaqueElement};
43
44use crate::content::{Alignment, Attributes, Block, Book, Inline, ListItem, NodeId, Row};
45
46#[derive(Clone, Debug, Default, Eq, Hash, PartialEq)]
53pub struct Atom(pub String);
54
55impl From<&str> for Atom {
56 fn from(value: &str) -> Self {
57 Atom(value.to_string())
58 }
59}
60
61impl From<String> for Atom {
62 fn from(value: String) -> Self {
63 Atom(value)
64 }
65}
66
67impl Borrow<str> for Atom {
68 fn borrow(&self) -> &str {
69 &self.0
70 }
71}
72
73impl ToCss for Atom {
74 fn to_css<W: fmt::Write>(&self, dest: &mut W) -> fmt::Result {
75 serialize_identifier(&self.0, dest)
76 }
77}
78
79impl PrecomputedHash for Atom {
80 fn precomputed_hash(&self) -> u32 {
81 fnv(&self.0)
82 }
83}
84
85fn fnv(name: &str) -> u32 {
88 let mut hash = 0x811c_9dc5u32;
89 for byte in name.as_bytes() {
90 hash ^= *byte as u32;
91 hash = hash.wrapping_mul(0x0100_0193);
92 }
93 hash
94}
95
96#[derive(Clone, Debug, Eq, PartialEq)]
100pub enum PseudoClass {}
101
102impl ToCss for PseudoClass {
103 fn to_css<W: fmt::Write>(&self, _dest: &mut W) -> fmt::Result {
104 match *self {}
105 }
106}
107
108impl NonTSPseudoClass for PseudoClass {
109 type Impl = Fleuron;
110
111 fn is_active_or_hover(&self) -> bool {
112 match *self {}
113 }
114
115 fn is_user_action_state(&self) -> bool {
116 match *self {}
117 }
118}
119
120pub use crate::content::PseudoElement;
121
122impl ToCss for PseudoElement {
123 fn to_css<W: fmt::Write>(&self, dest: &mut W) -> fmt::Result {
124 match self {
125 PseudoElement::FirstLetter => dest.write_str("::first-letter"),
126 PseudoElement::FirstLine => dest.write_str("::first-line"),
127 PseudoElement::Before => dest.write_str("::before"),
128 PseudoElement::After => dest.write_str("::after"),
129 }
130 }
131}
132
133pub const INLINE_ELEMENTS: [&str; 6] = ["code", "em", "strong", "a", "s", "span"];
137
138pub const BLOCK_ELEMENTS: [&str; 16] = [
140 "section",
141 "h1",
142 "h2",
143 "h3",
144 "h4",
145 "h5",
146 "h6",
147 "p",
148 "blockquote",
149 "pre",
150 "hr",
151 "img",
152 "ul",
153 "ol",
154 "li",
155 "table",
156];
157
158impl PseudoElementTrait for PseudoElement {
159 type Impl = Fleuron;
160}
161
162#[derive(Clone, Debug, Eq, PartialEq)]
164pub struct Fleuron;
165
166impl SelectorImpl for Fleuron {
167 type ExtraMatchingData<'a> = std::marker::PhantomData<&'a ()>;
168 type AttrValue = Atom;
169 type Identifier = Atom;
170 type LocalName = Atom;
171 type NamespaceUrl = Atom;
172 type NamespacePrefix = Atom;
173 type BorrowedLocalName = Atom;
174 type BorrowedNamespaceUrl = Atom;
175 type NonTSPseudoClass = PseudoClass;
176 type PseudoElement = PseudoElement;
177}
178
179pub const ELEMENTS: [&str; 30] = [
183 "book",
184 "section",
185 "notes",
186 "note",
187 "h1",
188 "h2",
189 "h3",
190 "h4",
191 "h5",
192 "h6",
193 "p",
194 "blockquote",
195 "pre",
196 "hr",
197 "img",
198 "ul",
199 "ol",
200 "li",
201 "table",
202 "thead",
203 "tbody",
204 "tr",
205 "th",
206 "td",
207 "code",
208 "em",
209 "strong",
210 "a",
211 "s",
212 "span",
213];
214
215fn past_last_id(book: &Book) -> u32 {
219 book.sections
220 .last()
221 .and_then(|section| book.subtree(section.id))
222 .map(|held| held.end)
223 .unwrap_or(1)
224}
225
226#[derive(Debug)]
229pub struct ElementNode {
230 pub name: &'static str,
232 pub id: NodeId,
234 pub attributes: Attributes,
236 pub parent: Option<usize>,
237 pub previous: Option<usize>,
238 pub next: Option<usize>,
239 pub first_child: Option<usize>,
240 pub has_text: bool,
242 pub align: Option<Alignment>,
245}
246
247#[derive(Debug, Default)]
250pub struct ElementTree {
251 nodes: Vec<ElementNode>,
252 anonymous: Vec<(NodeId, usize)>,
255 notes: NodeId,
258}
259
260impl ElementTree {
261 pub fn build(book: &Book) -> ElementTree {
264 let mut tree = ElementTree::default();
265 let root = tree.push(
266 "book",
267 NodeId::UNASSIGNED,
268 &Attributes::default(),
269 None,
270 false,
271 );
272 let sections: Vec<usize> = book
273 .sections
274 .iter()
275 .map(|section| {
276 let index = tree.push(
277 "section",
278 section.id,
279 §ion.attributes,
280 Some(root),
281 false,
282 );
283 let children = tree.blocks(§ion.blocks, index);
284 tree.link(index, &children);
285 index
286 })
287 .collect();
288 tree.link(root, §ions);
289 tree.notes = tree.area(root, past_last_id(book));
290 tree
291 }
292
293 fn area(&mut self, root: usize, past: u32) -> NodeId {
300 let id = NodeId::new(past);
301 self.push("notes", id, &Attributes::default(), Some(root), false);
302 id
303 }
304
305 pub fn notes(&self) -> NodeId {
307 self.notes
308 }
309
310 pub fn nodes(&self) -> &[ElementNode] {
312 &self.nodes
313 }
314
315 pub fn anonymous(&self) -> &[(NodeId, usize)] {
318 &self.anonymous
319 }
320
321 pub fn at(&self, index: usize) -> ElementRef<'_> {
323 ElementRef { tree: self, index }
324 }
325
326 fn blocks(&mut self, blocks: &[Block], parent: usize) -> Vec<usize> {
327 blocks
328 .iter()
329 .map(|block| match block {
330 Block::Heading {
331 id,
332 level,
333 inlines,
334 attributes,
335 ..
336 } => {
337 let name = match u8::from(*level) {
338 1 => "h1",
339 2 => "h2",
340 3 => "h3",
341 4 => "h4",
342 5 => "h5",
343 _ => "h6",
344 };
345 let index = self.push(name, *id, attributes, Some(parent), false);
346 let (children, has_text) = self.inlines(inlines, index);
347 self.link(index, &children);
348 self.nodes[index].has_text = has_text;
349 index
350 }
351 Block::Paragraph {
352 id,
353 inlines,
354 attributes,
355 ..
356 } => {
357 let index = self.push("p", *id, attributes, Some(parent), false);
358 let (children, has_text) = self.inlines(inlines, index);
359 self.link(index, &children);
360 self.nodes[index].has_text = has_text;
361 index
362 }
363 Block::Blockquote {
364 id,
365 blocks,
366 attributes,
367 ..
368 } => {
369 let index = self.push("blockquote", *id, attributes, Some(parent), false);
370 let children = self.blocks(blocks, index);
371 self.link(index, &children);
372 index
373 }
374 Block::CodeBlock {
375 id,
376 text,
377 attributes,
378 ..
379 } => self.push("pre", *id, attributes, Some(parent), !text.is_empty()),
380 Block::ThematicBreak { id, attributes, .. } => {
381 self.push("hr", *id, attributes, Some(parent), false)
382 }
383 Block::PageBreak { id, attributes, .. } => {
384 self.push("pagebreak", *id, attributes, Some(parent), false)
385 }
386 Block::ColumnBreak { id, attributes, .. } => {
387 self.push("columnbreak", *id, attributes, Some(parent), false)
388 }
389 Block::Image { id, attributes, .. } => {
390 self.push("img", *id, attributes, Some(parent), false)
391 }
392 Block::List {
393 id,
394 ordered,
395 tight,
396 items,
397 attributes,
398 ..
399 } => {
400 let name = if *ordered { "ol" } else { "ul" };
401 let index = self.push(name, *id, attributes, Some(parent), false);
402 let children = self.items(items, *tight, index);
403 self.link(index, &children);
404 index
405 }
406 Block::Table {
407 id,
408 head,
409 body,
410 attributes,
411 ..
412 } => {
413 let index = self.push("table", *id, attributes, Some(parent), false);
414 let mut groups = Vec::new();
415 for (group, rows, cell) in [("thead", head, "th"), ("tbody", body, "td")] {
416 if rows.is_empty() {
417 continue;
418 }
419 let at = self.push(
420 group,
421 NodeId::UNASSIGNED,
422 &Attributes::default(),
423 Some(index),
424 false,
425 );
426 let children = self.rows(rows, cell, at);
427 self.link(at, &children);
428 groups.push(at);
429 }
430 self.link(index, &groups);
431 index
432 }
433 })
434 .collect()
435 }
436
437 fn items(&mut self, items: &[ListItem], tight: bool, parent: usize) -> Vec<usize> {
440 let mut indices = Vec::with_capacity(items.len());
441 for item in items {
442 let index = self.push("li", item.id, &item.attributes, Some(parent), false);
443 let mut children = Vec::new();
444 for block in &item.blocks {
445 match block {
446 Block::Paragraph {
447 id,
448 inlines,
449 attributes,
450 ..
451 } if tight && attributes.is_empty() => {
452 let (inline, has_text) = self.inlines(inlines, index);
453 children.extend(inline);
454 self.nodes[index].has_text |= has_text;
455 self.anonymous.push((*id, index));
456 }
457 _ => children.extend(self.blocks(std::slice::from_ref(block), index)),
458 }
459 }
460 self.link(index, &children);
461 indices.push(index);
462 }
463 indices
464 }
465
466 fn rows(&mut self, rows: &[Row], cell: &'static str, parent: usize) -> Vec<usize> {
469 let mut indices = Vec::with_capacity(rows.len());
470 for row in rows {
471 let index = self.push("tr", row.id, &row.attributes, Some(parent), false);
472 let mut cells = Vec::with_capacity(row.cells.len());
473 for content in &row.cells {
474 let at = self.push(cell, content.id, &content.attributes, Some(index), false);
475 self.nodes[at].align = content.align;
476 let children = self.blocks(&content.blocks, at);
477 self.link(at, &children);
478 cells.push(at);
479 }
480 self.link(index, &cells);
481 indices.push(index);
482 }
483 indices
484 }
485
486 fn inlines(&mut self, inlines: &[Inline], parent: usize) -> (Vec<usize>, bool) {
489 let mut children = Vec::new();
490 let mut text = false;
491 for inline in inlines {
492 let (name, id, attributes, nested): (_, _, _, Option<&[Inline]>) = match inline {
493 Inline::Text { value, .. } => {
494 text |= !value.is_empty();
495 continue;
496 }
497 Inline::Break { .. } => continue,
498 Inline::Code {
499 id,
500 value,
501 attributes,
502 ..
503 } => {
504 let index = self.push("code", *id, attributes, Some(parent), !value.is_empty());
505 children.push(index);
506 continue;
507 }
508 Inline::Emphasis {
509 id,
510 children,
511 attributes,
512 ..
513 } => ("em", *id, attributes, Some(children)),
514 Inline::Strong {
515 id,
516 children,
517 attributes,
518 ..
519 } => ("strong", *id, attributes, Some(children)),
520 Inline::Link {
521 id,
522 children,
523 attributes,
524 ..
525 } => ("a", *id, attributes, Some(children)),
526 Inline::Strikethrough {
527 id,
528 children,
529 attributes,
530 ..
531 } => ("s", *id, attributes, Some(children)),
532 Inline::Span {
533 id,
534 children,
535 attributes,
536 ..
537 } => ("span", *id, attributes, Some(children)),
538 Inline::Note {
541 id,
542 blocks,
543 attributes,
544 ..
545 } => {
546 let index = self.push("note", *id, attributes, Some(parent), false);
547 let kids = self.blocks(blocks, index);
548 self.link(index, &kids);
549 children.push(index);
550 continue;
551 }
552 };
553 let index = self.push(name, id, attributes, Some(parent), false);
554 if let Some(nested) = nested {
555 let (kids, has_text) = self.inlines(nested, index);
556 self.link(index, &kids);
557 self.nodes[index].has_text = has_text;
558 }
559 children.push(index);
560 }
561 (children, text)
562 }
563
564 fn push(
565 &mut self,
566 name: &'static str,
567 id: NodeId,
568 attributes: &Attributes,
569 parent: Option<usize>,
570 has_text: bool,
571 ) -> usize {
572 self.nodes.push(ElementNode {
573 name,
574 id,
575 attributes: attributes.clone(),
576 parent,
577 previous: None,
578 next: None,
579 first_child: None,
580 has_text,
581 align: None,
582 });
583 self.nodes.len() - 1
584 }
585
586 fn link(&mut self, parent: usize, children: &[usize]) {
589 self.nodes[parent].first_child = children.first().copied();
590 for (position, index) in children.iter().enumerate() {
591 self.nodes[*index].previous = position.checked_sub(1).map(|p| children[p]);
592 self.nodes[*index].next = children.get(position + 1).copied();
593 }
594 }
595}
596
597#[derive(Clone, Copy)]
599pub struct ElementRef<'a> {
600 tree: &'a ElementTree,
601 pub index: usize,
603}
604
605impl ElementRef<'_> {
606 fn node(&self) -> &ElementNode {
607 &self.tree.nodes[self.index]
608 }
609
610 fn sibling(&self, which: fn(&ElementNode) -> Option<usize>) -> Option<Self> {
611 which(self.node()).map(|index| ElementRef {
612 tree: self.tree,
613 index,
614 })
615 }
616}
617
618impl fmt::Debug for ElementRef<'_> {
619 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
620 write!(f, "<{}>", self.node().name)
621 }
622}
623
624impl Element for ElementRef<'_> {
625 type Impl = Fleuron;
626
627 fn opaque(&self) -> OpaqueElement {
628 OpaqueElement::new(self.node())
629 }
630
631 fn parent_element(&self) -> Option<Self> {
632 self.sibling(|node| node.parent)
633 }
634
635 fn parent_node_is_shadow_root(&self) -> bool {
636 false
637 }
638
639 fn containing_shadow_host(&self) -> Option<Self> {
640 None
641 }
642
643 fn is_pseudo_element(&self) -> bool {
644 false
645 }
646
647 fn prev_sibling_element(&self) -> Option<Self> {
648 self.sibling(|node| node.previous)
649 }
650
651 fn next_sibling_element(&self) -> Option<Self> {
652 self.sibling(|node| node.next)
653 }
654
655 fn first_element_child(&self) -> Option<Self> {
656 self.sibling(|node| node.first_child)
657 }
658
659 fn is_html_element_in_html_document(&self) -> bool {
660 false
661 }
662
663 fn has_local_name(&self, name: &Atom) -> bool {
664 self.node().name == name.0
665 }
666
667 fn has_namespace(&self, ns: &Atom) -> bool {
668 ns.0.is_empty()
669 }
670
671 fn is_same_type(&self, other: &Self) -> bool {
672 self.node().name == other.node().name
673 }
674
675 fn attr_matches(
676 &self,
677 _ns: &NamespaceConstraint<&Atom>,
678 _local_name: &Atom,
679 _operation: &AttrSelectorOperation<&Atom>,
680 ) -> bool {
681 false
682 }
683
684 fn match_non_ts_pseudo_class(
685 &self,
686 pc: &PseudoClass,
687 _context: &mut MatchingContext<Fleuron>,
688 ) -> bool {
689 match *pc {}
690 }
691
692 fn match_pseudo_element(
696 &self,
697 _pe: &PseudoElement,
698 _context: &mut MatchingContext<Fleuron>,
699 ) -> bool {
700 false
701 }
702
703 fn apply_selector_flags(&self, _flags: ElementSelectorFlags) {}
704
705 fn is_link(&self) -> bool {
706 self.node().name == "a"
707 }
708
709 fn is_html_slot_element(&self) -> bool {
710 false
711 }
712
713 fn has_id(&self, id: &Atom, case_sensitivity: CaseSensitivity) -> bool {
714 self.node()
715 .attributes
716 .id
717 .as_ref()
718 .is_some_and(|mine| case_sensitivity.eq(mine.as_bytes(), id.0.as_bytes()))
719 }
720
721 fn has_class(&self, name: &Atom, case_sensitivity: CaseSensitivity) -> bool {
722 self.node()
723 .attributes
724 .classes
725 .iter()
726 .any(|mine| case_sensitivity.eq(mine.as_bytes(), name.0.as_bytes()))
727 }
728
729 fn has_custom_state(&self, _name: &Atom) -> bool {
730 false
731 }
732
733 fn imported_part(&self, _name: &Atom) -> Option<Atom> {
734 None
735 }
736
737 fn is_part(&self, _name: &Atom) -> bool {
738 false
739 }
740
741 fn is_empty(&self) -> bool {
742 self.node().first_child.is_none() && !self.node().has_text
743 }
744
745 fn is_root(&self) -> bool {
746 self.node().parent.is_none()
747 }
748
749 fn add_element_unique_hashes(&self, filter: &mut BloomFilter) -> bool {
753 let node = self.node();
754 let mut insert = |name: &str| filter.insert_hash(fnv(name) & BLOOM_HASH_MASK);
755 insert(node.name);
756 if let Some(id) = &node.attributes.id {
757 insert(id);
758 }
759 for class in &node.attributes.classes {
760 insert(class);
761 }
762 true
763 }
764}