@@ -151,7 +151,10 @@ impl<'a> XdvEvents for EngineState<'a> {
151151
152152 let do_init = match & mut self . state {
153153 State :: Invalid => false ,
154- State :: Initializing ( s) => s. cur_font_family_definition . is_none ( ) ,
154+ State :: Initializing ( s) => {
155+ s. cur_font_family_definition . is_none ( )
156+ && s. cur_font_family_tag_associations . is_none ( )
157+ }
155158 State :: Emitting ( _) => false ,
156159 } ;
157160
@@ -245,7 +248,10 @@ struct InitializationState {
245248 main_body_font_num : Option < i32 > ,
246249 /// Keyed by the "regular" font-num
247250 font_families : HashMap < FontNum , FontFamily > ,
251+ tag_associations : HashMap < Element , FontNum > ,
252+
248253 cur_font_family_definition : Option < FontFamilyBuilder > ,
254+ cur_font_family_tag_associations : Option < FontFamilyTagAssociator > ,
249255
250256 variables : HashMap < String , String > ,
251257}
@@ -262,7 +268,10 @@ impl Default for InitializationState {
262268 font_data : Default :: default ( ) ,
263269 main_body_font_num : None ,
264270 font_families : Default :: default ( ) ,
271+ tag_associations : Default :: default ( ) ,
272+
265273 cur_font_family_definition : None ,
274+ cur_font_family_tag_associations : None ,
266275
267276 variables : Default :: default ( ) ,
268277 }
@@ -380,6 +389,10 @@ impl InitializationState {
380389 self . handle_start_define_font_family ( )
381390 } else if contents == "tdux:endDefineFontFamily" {
382391 self . handle_end_define_font_family ( common)
392+ } else if contents == "tdux:startFontFamilyTagAssociations" {
393+ self . handle_start_font_family_tag_associations ( )
394+ } else if contents == "tdux:endFontFamilyTagAssociations" {
395+ self . handle_end_font_family_tag_associations ( common)
383396 } else if let Some ( _remainder) = contents. strip_prefix ( "tdux:provideFile " ) {
384397 tt_warning ! ( common. status, "ignoring too-soon tdux:provideFile special" ) ;
385398 Ok ( ( ) )
@@ -468,6 +481,30 @@ impl InitializationState {
468481 Ok ( ( ) )
469482 }
470483
484+ // "Font family tag associations", telling us which font family is the
485+ // default depending on which tag we're in. For instance, typical templates
486+ // will default to the monospace font inside `<code>` tags.
487+
488+ fn handle_start_font_family_tag_associations ( & mut self ) -> Result < ( ) > {
489+ self . cur_font_family_tag_associations = Some ( FontFamilyTagAssociator :: default ( ) ) ;
490+ Ok ( ( ) )
491+ }
492+
493+ fn handle_end_font_family_tag_associations ( & mut self , common : & mut Common ) -> Result < ( ) > {
494+ if let Some ( mut a) = self . cur_font_family_tag_associations . take ( ) {
495+ for ( k, v) in a. assoc . drain ( ) {
496+ self . tag_associations . insert ( k, v) ;
497+ }
498+ } else {
499+ tt_warning ! (
500+ common. status,
501+ "end of font-family tag-association block that didn't start"
502+ ) ;
503+ }
504+
505+ Ok ( ( ) )
506+ }
507+
471508 /// In the initialization state, this should only get called if we're in a
472509 /// font-family definition (in which case we're using the contents to learn
473510 /// the definition of a font family). Otherwise, the higher-level callback
@@ -479,24 +516,37 @@ impl InitializationState {
479516 _glyphs : & [ u16 ] ,
480517 _xs : & [ i32 ] ,
481518 _ys : & [ i32 ] ,
482- _common : & mut Common ,
519+ common : & mut Common ,
483520 ) -> Result < ( ) > {
484- let b = self . cur_font_family_definition . as_mut ( ) . unwrap ( ) ;
485-
486- if text. starts_with ( "bold-italic" ) {
487- b. bold_italic = Some ( font_num) ;
488- } else if text. starts_with ( "bold" ) {
489- b. bold = Some ( font_num) ;
490- } else if text. starts_with ( "italic" ) {
491- b. italic = Some ( font_num) ;
492- } else {
493- b. regular = Some ( font_num) ;
521+ if let Some ( b) = self . cur_font_family_definition . as_mut ( ) {
522+ if text. starts_with ( "bold-italic" ) {
523+ b. bold_italic = Some ( font_num) ;
524+ } else if text. starts_with ( "bold" ) {
525+ b. bold = Some ( font_num) ;
526+ } else if text. starts_with ( "italic" ) {
527+ b. italic = Some ( font_num) ;
528+ } else {
529+ b. regular = Some ( font_num) ;
494530
495- // Say that the "regular" font of the first font family definition
496- // is the main body font.
497- if self . main_body_font_num . is_none ( ) {
498- self . main_body_font_num = Some ( font_num) ;
531+ // Say that the "regular" font of the first font family definition
532+ // is the main body font.
533+ if self . main_body_font_num . is_none ( ) {
534+ self . main_body_font_num = Some ( font_num) ;
535+ }
499536 }
537+ } else if let Some ( a) = self . cur_font_family_tag_associations . as_mut ( ) {
538+ for tagname in text. split_whitespace ( ) {
539+ let el: Element = tagname. parse ( ) . unwrap ( ) ;
540+ a. assoc . insert ( el, font_num) ;
541+ }
542+ } else {
543+ // This shouldn't happen; the top-level processor should exit init
544+ // phase if it's invoked and none of the above cases hold.
545+ tt_warning ! (
546+ common. status,
547+ "internal bug; losing text `{}` in initialization phase" ,
548+ text
549+ ) ;
500550 }
501551
502552 Ok ( ( ) )
@@ -559,6 +609,7 @@ impl InitializationState {
559609 context,
560610 fonts : self . fonts ,
561611 font_families : self . font_families ,
612+ tag_associations : self . tag_associations ,
562613 rems_per_tex,
563614 font_data : self . font_data ,
564615 next_template_path : self . next_template_path ,
@@ -589,6 +640,7 @@ struct EmittingState {
589640
590641 /// Keyed by the "regular" font
591642 font_families : HashMap < FontNum , FontFamily > ,
643+ tag_associations : HashMap < Element , FontNum > ,
592644
593645 rems_per_tex : f32 ,
594646 font_data : HashMap < usize , FontData > ,
@@ -770,10 +822,21 @@ impl EmittingState {
770822
771823 let el = self . create_elem ( name, true , common) ;
772824
773- let new_item = ElementState {
774- elem : Some ( el) ,
775- origin,
776- ..* self . cur_elstate ( )
825+ let new_item = {
826+ let cur = self . cur_elstate ( ) ;
827+
828+ let font_family_id = self
829+ . tag_associations
830+ . get ( & el)
831+ . copied ( )
832+ . unwrap_or ( cur. font_family_id ) ;
833+
834+ ElementState {
835+ elem : Some ( el) ,
836+ origin,
837+ font_family_id,
838+ ..* cur
839+ }
777840 } ;
778841
779842 self . elem_stack . push ( new_item) ;
@@ -1034,11 +1097,24 @@ impl EmittingState {
10341097 }
10351098
10361099 let el = self . create_elem ( tagname, true , common) ;
1037- let mut elstate = ElementState {
1038- elem : Some ( el) ,
1039- origin : ElementOrigin :: Manual ,
1040- ..* self . cur_elstate ( )
1100+
1101+ let mut elstate = {
1102+ let cur = self . cur_elstate ( ) ;
1103+
1104+ let font_family_id = self
1105+ . tag_associations
1106+ . get ( & el)
1107+ . copied ( )
1108+ . unwrap_or ( cur. font_family_id ) ;
1109+
1110+ ElementState {
1111+ elem : Some ( el) ,
1112+ origin : ElementOrigin :: Manual ,
1113+ font_family_id,
1114+ ..* cur
1115+ }
10411116 } ;
1117+
10421118 let mut classes = Vec :: new ( ) ;
10431119 let mut styles = Vec :: new ( ) ;
10441120 let mut unquoted_attrs = Vec :: new ( ) ;
@@ -1971,3 +2047,8 @@ enum FamilyRelativeFontId {
19712047 /// family.
19722048 Other ( FontNum ) ,
19732049}
2050+
2051+ #[ derive( Debug , Default ) ]
2052+ struct FontFamilyTagAssociator {
2053+ assoc : HashMap < Element , FontNum > ,
2054+ }
0 commit comments