use pango::{FontDescription, Layout};
use crate::output::{
- cairo::{fsm::CairoFsmStyle, horz_align_to_pango, xr_to_pt},
+ cairo::{
+ fsm::{CairoFsm, CairoFsmStyle},
+ horz_align_to_pango, xr_to_pt,
+ },
page::Heading,
pivot::Axis2,
- OwnedItemCursor,
+ Item, OwnedItemCursor,
};
+#[derive(Clone, Debug)]
pub struct CairoPageStyle {
pub margins: EnumMap<Axis2, [usize; 2]>,
pub headings: [Heading; 2],
page_index: i32,
heading_heights: [usize; 2],
iter: Option<OwnedItemCursor>,
+ context: Option<Context>,
+ fsm: Option<CairoFsm>,
+ y: usize,
}
impl CairoPager {
- fn new(page_style: Arc<CairoPageStyle>, fsm_style: Arc<CairoFsmStyle>) -> Self {
+ fn new(mut page_style: Arc<CairoPageStyle>, mut fsm_style: Arc<CairoFsmStyle>) -> Self {
+ let heading_heights = measure_headings(&page_style, &fsm_style);
+ let total = heading_heights.iter().sum::<usize>();
+ if (0..fsm_style.size[Axis2::Y]).contains(&total) {
+ let fsm_style = Arc::make_mut(&mut fsm_style);
+ let page_style = Arc::make_mut(&mut page_style);
+ for i in 0..2 {
+ page_style.margins[Axis2::Y][i] += heading_heights[i];
+ }
+ fsm_style.size[Axis2::Y] -= total;
+ }
Self {
- heading_heights: measure_headings(&page_style, &fsm_style),
+ heading_heights,
page_style,
fsm_style,
page_index: 0,
iter: None,
}
}
+
+ fn add_page(&mut self, context: Context) {
+ assert!(self.context.is_none());
+ context.save().unwrap();
+ self.y = 0;
+
+ context.translate(
+ xr_to_pt(self.page_style.margins[Axis2::X][0]),
+ xr_to_pt(self.page_style.margins[Axis2::Y][0]),
+ );
+
+ let page_number = self.page_index + self.page_style.initial_page_number;
+ self.page_index += 1;
+
+ if self.heading_heights[0] > 0 {
+ render_heading(
+ &context,
+ &self.fsm_style.font,
+ &self.page_style.headings[0],
+ page_number,
+ self.fsm_style.size[Axis2::X],
+ 0, /* XXX*/
+ self.fsm_style.font_resolution,
+ );
+ }
+ if self.heading_heights[0] > 0 {
+ render_heading(
+ &context,
+ &self.fsm_style.font,
+ &self.page_style.headings[1],
+ page_number,
+ self.fsm_style.size[Axis2::X],
+ self.fsm_style.size[Axis2::Y] + self.fsm_style.object_spacing,
+ self.fsm_style.font_resolution,
+ );
+ }
+
+ self.context = Some(context);
+ self.run();
+ }
+
+ fn finish_page(&mut self) {
+ if let Some(context) = self.context.take() {
+ context.restore().unwrap();
+ }
+ }
+
+ fn add_item(&mut self, item: Arc<Item>) {
+ self.iter = Some(OwnedItemCursor::new(item));
+ self.run();
+ }
+
+ fn run(&mut self) {
+ if self.iter.is_none() || self.context.is_none() || self.y >= self.fsm_style.size[Axis2::Y]
+ {
+ return;
+ }
+
+ loop {
+ // Make sure we've got an object to render.
+ while self.fsm.is_none() {
+ // If there are no remaining objects to render, then we're done.
+ if self.iter.as_mut().unwrap().cur().is_none() {
+ self.iter = None;
+ return;
+ }
+
+ // Prepare to render the current object.
+ let fsm = CairoFsm::new(self.fsm_style.clone(), true, self.context.clone(), self)
+ }
+ }
+ }
}
fn measure_headings(page_style: &CairoPageStyle, fsm_style: &CairoFsmStyle) -> [usize; 2] {
layout.set_width(width as i32);
context.save().unwrap();
- context.translate(0.0, xr_to_pt(width));
+ context.translate(0.0, xr_to_pt(y + base_y));
pangocairo::functions::show_layout(context, &layout);
context.restore().unwrap();