diff --git a/src/export/pdf.rs b/src/export/pdf.rs index b8fc1e39d..aa3e08763 100644 --- a/src/export/pdf.rs +++ b/src/export/pdf.rs @@ -604,12 +604,12 @@ impl<'a, 'b> PageExporter<'a, 'b> { } fn write_frame(&mut self, frame: &Frame) { - if let Some(Role::Heading(level)) = frame.role() { + if let Some(Role::Heading { level, outlined: true }) = frame.role() { let heading = Heading { position: Point::new(self.state.transform.tx, self.state.transform.ty), content: frame.text(), page: self.page_ref, - level, + level: level.get(), }; if let Some(last) = self.exporter.heading_tree.last_mut() { diff --git a/src/frame.rs b/src/frame.rs index 7972b0697..934c3f22e 100644 --- a/src/frame.rs +++ b/src/frame.rs @@ -1,6 +1,7 @@ //! Finished layouts. use std::fmt::{self, Debug, Formatter, Write}; +use std::num::NonZeroUsize; use std::sync::Arc; use crate::eval::{Dict, Value}; @@ -71,7 +72,7 @@ impl Frame { /// group based on the number of elements in the frame. pub fn push_frame(&mut self, pos: Point, frame: impl FrameRepr) { if (self.elements.is_empty() || frame.as_ref().is_light()) - && frame.as_ref().role().is_none() + && frame.as_ref().role().map_or(true, Role::is_weak) { frame.inline(self, self.layer(), pos); } else { @@ -95,7 +96,7 @@ impl Frame { /// Add a frame at a position in the background. pub fn prepend_frame(&mut self, pos: Point, frame: impl FrameRepr) { if (self.elements.is_empty() || frame.as_ref().is_light()) - && frame.as_ref().role().is_none() + && frame.as_ref().role().map_or(true, Role::is_weak) { frame.inline(self, 0, pos); } else { @@ -412,8 +413,8 @@ impl Location { pub enum Role { /// A paragraph. Paragraph, - /// A heading with some level. - Heading(usize), + /// A heading with some level and whether it should be part of the outline. + Heading { level: NonZeroUsize, outlined: bool }, /// A generic block-level subdivision. GenericBlock, /// A generic inline subdivision. diff --git a/src/library/structure/heading.rs b/src/library/structure/heading.rs index af2b36268..24054f810 100644 --- a/src/library/structure/heading.rs +++ b/src/library/structure/heading.rs @@ -55,6 +55,11 @@ impl HeadingNode { pub const BELOW: Leveled> = Leveled::Value(Some(Ratio::new(0.55).into())); + /// Whether the heading appears in the outline. + pub const OUTLINED: bool = true; + /// Whether the heading is numbered. + pub const NUMBERED: bool = true; + fn construct(_: &mut Machine, args: &mut Args) -> TypResult { Ok(Content::show(Self { body: args.expect("body")?, @@ -65,14 +70,15 @@ impl HeadingNode { impl Show for HeadingNode { fn unguard(&self, sel: Selector) -> ShowNode { - let body = self.body.unguard(sel).role(Role::Heading(self.level.get())); - Self { body, ..*self }.pack() + Self { body: self.body.unguard(sel), ..*self }.pack() } - fn encode(&self, _: StyleChain) -> Dict { + fn encode(&self, styles: StyleChain) -> Dict { dict! { "level" => Value::Int(self.level.get() as i64), "body" => Value::Content(self.body.clone()), + "outlined" => Value::Bool(styles.get(Self::OUTLINED)), + "numbered" => Value::Bool(styles.get(Self::NUMBERED)), } } @@ -115,7 +121,12 @@ impl Show for HeadingNode { realized = realized.underlined(); } - realized = realized.styled_with_map(map).role(Role::Heading(self.level.get())); + let role = Role::Heading { + level: self.level, + outlined: styles.get(Self::OUTLINED), + }; + + realized = realized.styled_with_map(map).role(role); realized = realized.spaced( resolve!(Self::ABOVE).resolve(styles), resolve!(Self::BELOW).resolve(styles), diff --git a/src/model/layout.rs b/src/model/layout.rs index b4151c046..d8cf1cab7 100644 --- a/src/model/layout.rs +++ b/src/model/layout.rs @@ -231,9 +231,10 @@ impl Layout for LayoutNode { let hash = fxhash::hash64(&ctx.pins); let at = ctx.pins.cursor(); - let entry = StyleEntry::Barrier(Barrier::new(node.id())); - let mut result = node.0.layout(ctx, regions, entry.chain(&styles)); + let barrier = StyleEntry::Barrier(Barrier::new(node.id())); + let styles = barrier.chain(&styles); + let mut result = node.0.layout(ctx, regions, styles); if let Some(role) = styles.role() { result = result.map(|mut frames| { for frame in frames.iter_mut() {