pub mod fixed;
pub mod fixed_image;
pub mod fixed_line;
pub mod fixed_text;
pub mod footnote;
pub mod footer;
pub mod form;
pub mod header;
pub mod image;
pub mod list;
pub mod page_break;
pub mod paragraph;
pub mod section;
pub mod section_break;
pub mod spacer;
pub mod table;
pub mod toc;
use std::collections::HashMap;
use crate::{
backend::{FontRef, PdfBackend},
compliance::ua::{AccessibilityConfig, StructTag, StructureTree},
fonts::FontRegistry,
layout::{FixedBox, GlyphUsageTracker, PageFlow, TextLayoutEngine},
page::PageLayout,
styles::{DocumentStyle, RgbColor},
};
#[derive(Debug, Clone)]
pub enum LayoutMode {
Flow,
Fixed(FixedBox),
}
#[derive(Debug, Clone)]
pub struct RenderResult {
pub has_more: bool,
}
impl RenderResult {
pub fn done() -> Self { Self { has_more: false } }
pub fn more() -> Self { Self { has_more: true } }
}
pub struct RenderContext {
pub backend: Box<dyn PdfBackend>,
pub font_map: HashMap<String, FontRef>,
pub flow: PageFlow,
pub layout: PageLayout,
pub layout_engine: TextLayoutEngine,
pub style: DocumentStyle,
pub fonts: FontRegistry,
pub force_page_break: bool,
pub default_font_family: String,
pub page_number: u32,
pub total_pages: u32,
pub resume_index: usize,
pub glyph_tracker: GlyphUsageTracker,
pub reserved_footnotes_mm: f64,
pub ua_config: AccessibilityConfig,
pub ua_events: StructureTree,
pub mcid_counter: u32,
pub last_heading_level: Option<u8>,
}
impl RenderContext {
pub fn reset_resume(&mut self) {
self.resume_index = 0;
}
pub fn ua_enabled(&self) -> bool {
self.ua_config.enabled
}
pub fn next_mcid(&mut self) -> u32 {
let mcid = self.mcid_counter;
self.mcid_counter += 1;
mcid
}
pub fn ua_tag_element(&mut self, tag: StructTag, alt: Option<String>) -> u32 {
let mcid = self.next_mcid();
let page_idx = self.page_number as usize - 1;
self.ua_events.begin_group(tag, alt);
self.ua_events.add_content_ref(mcid, page_idx);
self.ua_events.end_group();
mcid
}
pub fn ua_begin_group(&mut self, tag: StructTag, alt: Option<String>) {
self.ua_events.begin_group(tag, alt);
}
pub fn ua_content_ref(&mut self, mcid: u32) {
let page_idx = self.page_number as usize - 1;
self.ua_events.add_content_ref(mcid, page_idx);
}
pub fn ua_end_group(&mut self) {
self.ua_events.end_group();
}
pub fn get_font_ref(&self, bold: bool, italic: bool) -> Option<FontRef> {
self.get_font_ref_for(&self.default_font_family.clone(), bold, italic)
}
pub fn get_font_ref_for(&self, family: &str, bold: bool, italic: bool) -> Option<FontRef> {
if bold && italic {
self.font_map.get(&format!("{family}::bold_italic"))
.or_else(|| self.font_map.get(&format!("{family}::bold")))
.or_else(|| self.font_map.get(&format!("{family}::italic")))
.or_else(|| self.font_map.get(&format!("{family}::regular")))
.copied()
} else if bold {
self.font_map.get(&format!("{family}::bold"))
.or_else(|| self.font_map.get(&format!("{family}::regular")))
.copied()
} else if italic {
self.font_map.get(&format!("{family}::italic"))
.or_else(|| self.font_map.get(&format!("{family}::regular")))
.copied()
} else {
self.font_map.get(&format!("{family}::regular")).copied()
}
}
pub fn draw_text(
&mut self,
text: &str,
x_mm: f64,
y_mm: f64,
font_size_pt: f64,
font_ref: FontRef,
color: &RgbColor,
) -> crate::Result<()> {
self.backend.draw_text(text, x_mm, y_mm, font_size_pt, font_ref, color, 0.0)
}
pub fn draw_text_spaced(
&mut self,
text: &str,
x_mm: f64,
y_mm: f64,
font_size_pt: f64,
font_ref: FontRef,
color: &RgbColor,
letter_spacing_pt: f32,
) -> crate::Result<()> {
self.backend.draw_text(text, x_mm, y_mm, font_size_pt, font_ref, color, letter_spacing_pt)
}
pub fn draw_hline(
&mut self,
x0_mm: f64,
x1_mm: f64,
y_mm: f64,
width_pt: f32,
color: &RgbColor,
) -> crate::Result<()> {
self.backend.draw_line(x0_mm, y_mm, x1_mm, y_mm, width_pt, color)
}
pub fn draw_vline(
&mut self,
x_mm: f64,
y0_mm: f64,
y1_mm: f64,
width_pt: f32,
color: &RgbColor,
) -> crate::Result<()> {
self.backend.draw_line(x_mm, y0_mm, x_mm, y1_mm, width_pt, color)
}
}
pub trait Element {
fn layout_mode(&self) -> LayoutMode {
LayoutMode::Flow
}
fn estimated_height_mm(&self) -> f64 {
0.0
}
fn as_section_info(&self) -> Option<(u8, &str)> {
None
}
fn inject_toc_entries(&mut self, _entries: &[crate::elements::toc::TocEntry]) {}
fn render(&self, ctx: &mut RenderContext) -> crate::Result<RenderResult>;
}