1use std::any::{Any, TypeId};
2use std::fmt::{self, Debug, Formatter};
3use std::hash::{Hash, Hasher};
4use std::{mem, ptr};
5
6use comemo::Tracked;
7use ecow::{EcoString, EcoVec, eco_vec};
8use rustc_hash::FxHashMap;
9use smallvec::SmallVec;
10use typst_syntax::Span;
11use typst_utils::LazyHash;
12
13use crate::diag::{SourceResult, Trace, Tracepoint};
14use crate::engine::Engine;
15use crate::foundations::{
16 Content, Context, Element, Field, Func, NativeElement, OneOrMultiple, Packed,
17 RefableProperty, Repr, Selector, SettableProperty, Target, cast, ty,
18};
19use crate::introspection::TagElem;
20
21#[ty(cast)]
23#[derive(Default, Clone, PartialEq, Hash)]
24pub struct Styles(EcoVec<LazyHash<Style>>);
25
26impl Styles {
27 pub const fn new() -> Self {
29 Self(EcoVec::new())
30 }
31
32 pub fn is_empty(&self) -> bool {
34 self.0.is_empty()
35 }
36
37 pub fn iter(&self) -> impl Iterator<Item = &Style> {
39 self.0.iter().map(|style| &**style)
40 }
41
42 pub fn as_slice(&self) -> &[LazyHash<Style>] {
44 self.0.as_slice()
45 }
46
47 pub fn set<E, const I: u8>(&mut self, field: Field<E, I>, value: E::Type)
53 where
54 E: SettableProperty<I>,
55 E::Type: Debug + Clone + Hash + Send + Sync + 'static,
56 {
57 self.push(Property::new(field, value));
58 }
59
60 pub fn push(&mut self, style: impl Into<Style>) {
62 self.0.push(LazyHash::new(style.into()));
63 }
64
65 pub fn unset(&mut self) {
67 self.0.pop();
68 }
69
70 pub fn apply(&mut self, mut outer: Self) {
72 outer.0.extend(mem::take(self).0);
73 *self = outer;
74 }
75
76 pub fn apply_one(&mut self, outer: Style) {
78 self.0.insert(0, LazyHash::new(outer));
79 }
80
81 pub fn spanned(mut self, span: Span) -> Self {
83 for entry in self.0.make_mut() {
84 if let Style::Property(property) = &mut **entry {
85 property.span = span;
86 }
87 }
88 self
89 }
90
91 pub fn outside(mut self) -> Self {
93 for entry in self.0.make_mut() {
94 match &mut **entry {
95 Style::Property(property) => property.outside = true,
96 Style::Recipe(recipe) => recipe.outside = true,
97 _ => {}
98 }
99 }
100 self
101 }
102
103 pub fn liftable(mut self) -> Self {
105 for entry in self.0.make_mut() {
106 if let Style::Property(property) = &mut **entry {
107 property.liftable = true;
108 }
109 }
110 self
111 }
112
113 pub fn has<E: NativeElement, const I: u8>(&self, _: Field<E, I>) -> bool {
115 let elem = E::ELEM;
116 self.0
117 .iter()
118 .filter_map(|style| style.property())
119 .any(|property| property.is_of(elem) && property.id == I)
120 }
121
122 pub fn root(children: &[(&Content, StyleChain)], initial: StyleChain) -> Styles {
150 let base = StyleChain::trunk_from_pairs(children).unwrap_or(initial).to_map();
152
153 let trunk_len = initial
157 .to_map()
158 .as_slice()
159 .iter()
160 .zip(base.as_slice())
161 .take_while(|&(a, b)| a == b)
162 .count();
163
164 base.into_iter()
166 .enumerate()
167 .filter(|(i, style)| {
168 let initial = *i < trunk_len;
169 style.outside() && (initial || style.liftable())
170 })
171 .map(|(_, style)| style)
172 .collect()
173 }
174}
175
176impl From<LazyHash<Style>> for Styles {
177 fn from(style: LazyHash<Style>) -> Self {
178 Self(eco_vec![style])
179 }
180}
181
182impl From<Style> for Styles {
183 fn from(style: Style) -> Self {
184 Self(eco_vec![LazyHash::new(style)])
185 }
186}
187
188impl IntoIterator for Styles {
189 type Item = LazyHash<Style>;
190 type IntoIter = ecow::vec::IntoIter<Self::Item>;
191
192 fn into_iter(self) -> Self::IntoIter {
193 self.0.into_iter()
194 }
195}
196
197impl FromIterator<LazyHash<Style>> for Styles {
198 fn from_iter<T: IntoIterator<Item = LazyHash<Style>>>(iter: T) -> Self {
199 Self(iter.into_iter().collect())
200 }
201}
202
203impl Debug for Styles {
204 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
205 f.write_str("Styles ")?;
206 f.debug_list().entries(&self.0).finish()
207 }
208}
209
210impl Repr for Styles {
211 fn repr(&self) -> EcoString {
212 "..".into()
213 }
214}
215
216#[derive(Clone, Hash)]
218pub enum Style {
219 Property(Property),
221 Recipe(Recipe),
223 Revocation(RecipeIndex),
229}
230
231impl Style {
232 pub fn property(&self) -> Option<&Property> {
234 match self {
235 Self::Property(property) => Some(property),
236 _ => None,
237 }
238 }
239
240 pub fn recipe(&self) -> Option<&Recipe> {
242 match self {
243 Self::Recipe(recipe) => Some(recipe),
244 _ => None,
245 }
246 }
247
248 pub fn span(&self) -> Span {
250 match self {
251 Self::Property(property) => property.span,
252 Self::Recipe(recipe) => recipe.span,
253 Self::Revocation(_) => Span::detached(),
254 }
255 }
256
257 pub fn element(&self) -> Option<Element> {
260 match self {
261 Style::Property(property) => Some(property.elem),
262 Style::Recipe(recipe) => match recipe.selector {
263 Some(Selector::Elem(elem, _)) => Some(elem),
264 _ => None,
265 },
266 Style::Revocation(_) => None,
267 }
268 }
269
270 pub fn liftable(&self) -> bool {
273 match self {
274 Self::Property(property) => property.liftable,
275 Self::Recipe(_) => true,
276 Self::Revocation(_) => false,
277 }
278 }
279
280 pub fn outside(&self) -> bool {
283 match self {
284 Self::Property(property) => property.outside,
285 Self::Recipe(recipe) => recipe.outside,
286 Self::Revocation(_) => false,
287 }
288 }
289
290 pub fn wrap(self) -> LazyHash<Style> {
292 LazyHash::new(self)
293 }
294}
295
296impl Debug for Style {
297 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
298 match self {
299 Self::Property(property) => property.fmt(f),
300 Self::Recipe(recipe) => recipe.fmt(f),
301 Self::Revocation(guard) => guard.fmt(f),
302 }
303 }
304}
305
306impl From<Property> for Style {
307 fn from(property: Property) -> Self {
308 Self::Property(property)
309 }
310}
311
312impl From<Recipe> for Style {
313 fn from(recipe: Recipe) -> Self {
314 Self::Recipe(recipe)
315 }
316}
317
318#[derive(Clone, Hash)]
320pub struct Property {
321 elem: Element,
323 id: u8,
325 value: Block,
327 span: Span,
329 liftable: bool,
331 outside: bool,
333}
334
335impl Property {
336 pub fn new<E, const I: u8>(_: Field<E, I>, value: E::Type) -> Self
338 where
339 E: SettableProperty<I>,
340 E::Type: Debug + Clone + Hash + Send + Sync + 'static,
341 {
342 Self {
343 elem: E::ELEM,
344 id: I,
345 value: Block::new(value),
346 span: Span::detached(),
347 liftable: false,
348 outside: false,
349 }
350 }
351
352 pub fn is(&self, elem: Element, id: u8) -> bool {
354 self.elem == elem && self.id == id
355 }
356
357 pub fn is_of(&self, elem: Element) -> bool {
359 self.elem == elem
360 }
361
362 pub fn wrap(self) -> LazyHash<Style> {
364 Style::Property(self).wrap()
365 }
366}
367
368impl Debug for Property {
369 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
370 write!(
371 f,
372 "Set({}.{}: ",
373 self.elem.name(),
374 self.elem.field_name(self.id).unwrap_or("internal")
375 )?;
376 self.value.fmt(f)?;
377 write!(f, ")")
378 }
379}
380
381#[derive(Hash)]
387struct Block(Box<dyn Blockable>);
388
389impl Block {
390 fn new<T: Blockable>(value: T) -> Self {
392 Self(Box::new(value))
393 }
394
395 fn downcast<T: 'static>(&self, func: Element, id: u8) -> &T {
397 self.0
398 .as_any()
399 .downcast_ref()
400 .unwrap_or_else(|| block_wrong_type(func, id, self))
401 }
402}
403
404impl Debug for Block {
405 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
406 self.0.fmt(f)
407 }
408}
409
410impl Clone for Block {
411 fn clone(&self) -> Self {
412 self.0.dyn_clone()
413 }
414}
415
416trait Blockable: Debug + Send + Sync + 'static {
421 fn as_any(&self) -> &dyn Any;
423
424 fn dyn_hash(&self, state: &mut dyn Hasher);
426
427 fn dyn_clone(&self) -> Block;
429}
430
431impl<T: Debug + Clone + Hash + Send + Sync + 'static> Blockable for T {
432 fn as_any(&self) -> &dyn Any {
433 self
434 }
435
436 fn dyn_hash(&self, mut state: &mut dyn Hasher) {
437 TypeId::of::<Self>().hash(&mut state);
440 self.hash(&mut state);
441 }
442
443 fn dyn_clone(&self) -> Block {
444 Block(Box::new(self.clone()))
445 }
446}
447
448impl Hash for dyn Blockable {
449 fn hash<H: Hasher>(&self, state: &mut H) {
450 self.dyn_hash(state);
451 }
452}
453
454#[derive(Clone, PartialEq, Hash)]
456pub struct Recipe {
457 selector: Option<Selector>,
463 transform: Transformation,
465 span: Span,
467 outside: bool,
470}
471
472impl Recipe {
473 pub fn new(
475 selector: Option<Selector>,
476 transform: Transformation,
477 span: Span,
478 ) -> Self {
479 Self { selector, transform, span, outside: false }
480 }
481
482 pub fn selector(&self) -> Option<&Selector> {
484 self.selector.as_ref()
485 }
486
487 pub fn transform(&self) -> &Transformation {
489 &self.transform
490 }
491
492 pub fn span(&self) -> Span {
494 self.span
495 }
496
497 pub fn apply(
499 &self,
500 engine: &mut Engine,
501 context: Tracked<Context>,
502 content: Content,
503 ) -> SourceResult<Content> {
504 let mut content = match &self.transform {
505 Transformation::Content(content) => content.clone(),
506 Transformation::Func(func) => {
507 let mut result = func.call(engine, context, [content.clone()]);
508 if self.selector.is_some() {
509 let point = || Tracepoint::Show(content.func().name().into());
510 result = result.trace(engine.world, point, content.span());
511 }
512 result?.display()
513 }
514 Transformation::Style(styles) => content.styled_with_map(styles.clone()),
515 };
516 if content.span().is_detached() {
517 content = content.spanned(self.span);
518 }
519 Ok(content)
520 }
521}
522
523impl Debug for Recipe {
524 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
525 f.write_str("Show(")?;
526 if let Some(selector) = &self.selector {
527 selector.fmt(f)?;
528 f.write_str(", ")?;
529 }
530 self.transform.fmt(f)?;
531 f.write_str(")")
532 }
533}
534
535#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
537pub struct RecipeIndex(pub usize);
538
539#[derive(Clone, PartialEq, Hash)]
541pub enum Transformation {
542 Content(Content),
544 Func(Func),
546 Style(Styles),
548}
549
550impl Debug for Transformation {
551 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
552 match self {
553 Self::Content(content) => content.fmt(f),
554 Self::Func(func) => func.fmt(f),
555 Self::Style(styles) => styles.fmt(f),
556 }
557 }
558}
559
560cast! {
561 Transformation,
562 content: Content => Self::Content(content),
563 func: Func => Self::Func(func),
564}
565
566#[derive(Default, Copy, Clone, Hash)]
574pub struct StyleChain<'a> {
575 head: &'a [LazyHash<Style>],
577 tail: Option<&'a Self>,
579}
580
581impl<'a> StyleChain<'a> {
582 pub fn new(root: &'a Styles) -> Self {
584 Self { head: &root.0, tail: None }
585 }
586
587 pub fn get<E, const I: u8>(self, field: Field<E, I>) -> E::Type
598 where
599 E: SettableProperty<I>,
600 E::Type: Copy,
601 {
602 self.get_cloned(field)
603 }
604
605 pub fn get_cloned<E, const I: u8>(self, _: Field<E, I>) -> E::Type
610 where
611 E: SettableProperty<I>,
612 {
613 if let Some(fold) = E::FOLD {
614 self.get_folded::<E::Type>(E::ELEM, I, fold, E::default())
615 } else {
616 self.get_unfolded::<E::Type>(E::ELEM, I)
617 .cloned()
618 .unwrap_or_else(E::default)
619 }
620 }
621
622 pub fn get_ref<E, const I: u8>(self, _: Field<E, I>) -> &'a E::Type
627 where
628 E: RefableProperty<I>,
629 {
630 self.get_unfolded(E::ELEM, I).unwrap_or_else(|| E::default_ref())
631 }
632
633 pub fn resolve<E, const I: u8>(
635 self,
636 field: Field<E, I>,
637 ) -> <E::Type as Resolve>::Output
638 where
639 E: SettableProperty<I>,
640 E::Type: Resolve,
641 {
642 self.get_cloned(field).resolve(self)
643 }
644
645 fn get_unfolded<T: 'static>(self, func: Element, id: u8) -> Option<&'a T> {
648 self.find(func, id).map(|block| block.downcast(func, id))
649 }
650
651 fn get_folded<T: 'static + Clone>(
654 self,
655 func: Element,
656 id: u8,
657 fold: fn(T, T) -> T,
658 default: T,
659 ) -> T {
660 let iter = self
661 .properties(func, id)
662 .map(|block| block.downcast::<T>(func, id).clone());
663
664 if let Some(folded) = iter.reduce(fold) { fold(folded, default) } else { default }
665 }
666
667 fn find(self, func: Element, id: u8) -> Option<&'a Block> {
669 self.properties(func, id).next()
670 }
671
672 fn properties(self, func: Element, id: u8) -> impl Iterator<Item = &'a Block> {
674 self.entries()
675 .filter_map(|style| style.property())
676 .filter(move |property| property.is(func, id))
677 .map(|property| &property.value)
678 }
679
680 pub fn chain<'b, C>(&'b self, local: &'b C) -> StyleChain<'b>
686 where
687 C: Chainable + ?Sized,
688 {
689 Chainable::chain(local, self)
690 }
691
692 pub fn entries(self) -> Entries<'a> {
694 Entries { inner: [].as_slice().iter(), links: self.links() }
695 }
696
697 pub fn recipes(self) -> impl Iterator<Item = &'a Recipe> {
699 self.entries().filter_map(|style| style.recipe())
700 }
701
702 pub fn links(self) -> Links<'a> {
704 Links(Some(self))
705 }
706
707 pub fn to_map(self) -> Styles {
709 let mut styles: EcoVec<_> = self.entries().cloned().collect();
710 styles.make_mut().reverse();
711 Styles(styles)
712 }
713
714 pub fn suffix(self, len: usize) -> Styles {
717 let mut styles = EcoVec::new();
718 let take = self.links().count().saturating_sub(len);
719 for link in self.links().take(take) {
720 styles.extend(link.iter().cloned().rev());
721 }
722 styles.make_mut().reverse();
723 Styles(styles)
724 }
725
726 pub fn pop(&mut self) {
728 *self = self.tail.copied().unwrap_or_default();
729 }
730
731 pub fn trunk(iter: impl IntoIterator<Item = Self>) -> Option<Self> {
733 let mut iter = iter.into_iter();
735 let mut trunk = iter.next()?;
736 let mut depth = trunk.links().count();
737
738 for mut chain in iter {
739 let len = chain.links().count();
740 if len < depth {
741 for _ in 0..depth - len {
742 trunk.pop();
743 }
744 depth = len;
745 } else if len > depth {
746 for _ in 0..len - depth {
747 chain.pop();
748 }
749 }
750
751 while depth > 0 && chain != trunk {
752 trunk.pop();
753 chain.pop();
754 depth -= 1;
755 }
756 }
757
758 Some(trunk)
759 }
760
761 pub fn trunk_from_pairs(iter: &[(&Content, Self)]) -> Option<Self> {
765 Self::trunk(iter.iter().filter(|(c, _)| !c.is::<TagElem>()).map(|&(_, s)| s))
766 }
767}
768
769impl Debug for StyleChain<'_> {
770 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
771 f.write_str("StyleChain ")?;
772 f.debug_list()
773 .entries(self.entries().collect::<Vec<_>>().into_iter().rev())
774 .finish()
775 }
776}
777
778impl PartialEq for StyleChain<'_> {
779 fn eq(&self, other: &Self) -> bool {
780 ptr::eq(self.head, other.head)
781 && match (self.tail, other.tail) {
782 (Some(a), Some(b)) => ptr::eq(a, b),
783 (None, None) => true,
784 _ => false,
785 }
786 }
787}
788
789pub trait Chainable {
791 fn chain<'a>(&'a self, outer: &'a StyleChain<'_>) -> StyleChain<'a>;
793}
794
795impl Chainable for LazyHash<Style> {
796 fn chain<'a>(&'a self, outer: &'a StyleChain<'_>) -> StyleChain<'a> {
797 StyleChain {
798 head: std::slice::from_ref(self),
799 tail: Some(outer),
800 }
801 }
802}
803
804impl Chainable for [LazyHash<Style>] {
805 fn chain<'a>(&'a self, outer: &'a StyleChain<'_>) -> StyleChain<'a> {
806 if self.is_empty() {
807 *outer
808 } else {
809 StyleChain { head: self, tail: Some(outer) }
810 }
811 }
812}
813
814impl<const N: usize> Chainable for [LazyHash<Style>; N] {
815 fn chain<'a>(&'a self, outer: &'a StyleChain<'_>) -> StyleChain<'a> {
816 Chainable::chain(self.as_slice(), outer)
817 }
818}
819
820impl Chainable for Styles {
821 fn chain<'a>(&'a self, outer: &'a StyleChain<'_>) -> StyleChain<'a> {
822 Chainable::chain(self.0.as_slice(), outer)
823 }
824}
825
826pub struct Entries<'a> {
828 inner: std::slice::Iter<'a, LazyHash<Style>>,
829 links: Links<'a>,
830}
831
832impl<'a> Iterator for Entries<'a> {
833 type Item = &'a LazyHash<Style>;
834
835 fn next(&mut self) -> Option<Self::Item> {
836 loop {
837 if let Some(entry) = self.inner.next_back() {
838 return Some(entry);
839 }
840
841 match self.links.next() {
842 Some(next) => self.inner = next.iter(),
843 None => return None,
844 }
845 }
846 }
847}
848
849pub struct Links<'a>(Option<StyleChain<'a>>);
851
852impl<'a> Iterator for Links<'a> {
853 type Item = &'a [LazyHash<Style>];
854
855 fn next(&mut self) -> Option<Self::Item> {
856 let StyleChain { head, tail } = self.0?;
857 self.0 = tail.copied();
858 Some(head)
859 }
860}
861
862pub trait Resolve {
864 type Output;
866
867 fn resolve(self, styles: StyleChain) -> Self::Output;
869}
870
871impl<T: Resolve> Resolve for Option<T> {
872 type Output = Option<T::Output>;
873
874 fn resolve(self, styles: StyleChain) -> Self::Output {
875 self.map(|v| v.resolve(styles))
876 }
877}
878
879pub trait Fold {
893 fn fold(self, outer: Self) -> Self;
895}
896
897impl Fold for bool {
898 fn fold(self, _: Self) -> Self {
899 self
900 }
901}
902
903impl<T: Fold> Fold for Option<T> {
904 fn fold(self, outer: Self) -> Self {
905 match (self, outer) {
906 (Some(inner), Some(outer)) => Some(inner.fold(outer)),
907 (inner, _) => inner,
910 }
911 }
912}
913
914impl<T> Fold for Vec<T> {
915 fn fold(self, mut outer: Self) -> Self {
916 outer.extend(self);
917 outer
918 }
919}
920
921impl<T, const N: usize> Fold for SmallVec<[T; N]> {
922 fn fold(self, mut outer: Self) -> Self {
923 outer.extend(self);
924 outer
925 }
926}
927
928impl<T> Fold for OneOrMultiple<T> {
929 fn fold(self, mut outer: Self) -> Self {
930 outer.0.extend(self.0);
931 outer
932 }
933}
934
935pub type FoldFn<T> = fn(T, T) -> T;
937
938pub trait AlternativeFold {
950 fn fold_or(self, outer: Self) -> Self;
953}
954
955impl<T: Fold> AlternativeFold for Option<T> {
956 fn fold_or(self, outer: Self) -> Self {
957 match (self, outer) {
958 (Some(inner), Some(outer)) => Some(inner.fold(outer)),
959 (inner, outer) => inner.or(outer),
962 }
963 }
964}
965
966#[derive(Debug, Default, Copy, Clone, PartialEq, Hash)]
968pub struct Depth(pub usize);
969
970impl Fold for Depth {
971 fn fold(self, outer: Self) -> Self {
972 Self(outer.0 + self.0)
973 }
974}
975
976#[cold]
977fn block_wrong_type(func: Element, id: u8, value: &Block) -> ! {
978 panic!(
979 "attempted to read a value of a different type than was written {}.{}: {:?}",
980 func.name(),
981 func.field_name(id).unwrap(),
982 value
983 )
984}
985
986pub struct NativeRuleMap {
988 rules: FxHashMap<(Element, Target), NativeShowRule>,
989}
990
991pub type ShowFn<T> = fn(
993 elem: &Packed<T>,
994 engine: &mut Engine,
995 styles: StyleChain,
996) -> SourceResult<Content>;
997
998impl NativeRuleMap {
999 pub fn new() -> Self {
1006 let mut rules = Self { rules: FxHashMap::default() };
1007
1008 rules.register_builtin(crate::foundations::CONTEXT_RULE);
1011
1012 rules.register_builtin(crate::introspection::COUNTER_DISPLAY_RULE);
1016
1017 rules.register_empty::<crate::introspection::CounterUpdateElem>();
1019 rules.register_empty::<crate::introspection::StateUpdateElem>();
1020 rules.register_empty::<crate::introspection::MetadataElem>();
1021 rules.register_empty::<crate::model::PrefixInfo>();
1022
1023 rules
1024 }
1025
1026 fn register_empty<T: NativeElement>(&mut self) {
1028 self.register_builtin::<T>(|_, _, _| Ok(Content::empty()));
1029 }
1030
1031 fn register_builtin<T: NativeElement>(&mut self, f: ShowFn<T>) {
1033 self.register(Target::Paged, f);
1034 self.register(Target::Html, f);
1035 }
1036
1037 pub fn register<T: NativeElement>(&mut self, target: Target, f: ShowFn<T>) {
1041 let res = self.rules.insert((T::ELEM, target), NativeShowRule::new(f));
1042 if res.is_some() {
1043 panic!(
1044 "duplicate native show rule for `{}` on {target:?} target",
1045 T::ELEM.name()
1046 )
1047 }
1048 }
1049
1050 pub fn get(&self, target: Target, content: &Content) -> Option<NativeShowRule> {
1053 self.rules.get(&(content.func(), target)).copied()
1054 }
1055}
1056
1057impl Default for NativeRuleMap {
1058 fn default() -> Self {
1059 Self::new()
1060 }
1061}
1062
1063pub use rule::NativeShowRule;
1064
1065mod rule {
1066 use super::*;
1067
1068 #[derive(Copy, Clone)]
1070 pub struct NativeShowRule {
1071 elem: Element,
1073 f: unsafe fn(
1075 elem: &Content,
1076 engine: &mut Engine,
1077 styles: StyleChain,
1078 ) -> SourceResult<Content>,
1079 }
1080
1081 impl NativeShowRule {
1082 pub fn new<T: NativeElement>(f: ShowFn<T>) -> Self {
1084 Self {
1085 elem: T::ELEM,
1086 #[allow(clippy::missing_transmute_annotations)]
1092 f: unsafe { std::mem::transmute(f) },
1093 }
1094 }
1095
1096 pub fn apply(
1099 &self,
1100 content: &Content,
1101 engine: &mut Engine,
1102 styles: StyleChain,
1103 ) -> SourceResult<Content> {
1104 assert_eq!(content.elem(), self.elem);
1105
1106 unsafe { (self.f)(content, engine, styles) }
1108 }
1109 }
1110}