1use std::collections::BTreeMap;
17use std::sync::Arc;
18
19use crate::content::{Block, Book, Inline, NodeId, block_id, cell_blocks, notes_in_inlines};
20use crate::pages::{DrawItem, PageBox};
21use crate::style::{ComputedStyle, StyleTree};
22
23use super::Paginator;
24use super::build::{Builder, children, decorate};
25use super::flow::{Flow, Placed};
26use super::fragment::{Fragment, Marker};
27
28pub(crate) const UNSETTLED: &str = "The notes are numbered by page and the numbering did not \
31 settle. The numbers are the ones of the last layout.";
32
33#[derive(Debug)]
39pub struct Note {
40 pub node: NodeId,
42 pub number: u32,
44 pub fragments: Vec<Fragment>,
46}
47
48impl Note {
49 pub(super) fn height(&self, from: usize, under: bool) -> f32 {
54 (from..self.fragments.len())
55 .map(|index| self.step(index, under || index > from))
56 .sum()
57 }
58
59 pub(super) fn step(&self, index: usize, under: bool) -> f32 {
62 let fragment = &self.fragments[index];
63 let lead = if under { fragment.lead } else { 0.0 };
64 lead + fragment.fixed + fragment.height
65 }
66}
67
68#[derive(Debug, Clone, Default, PartialEq, Eq)]
74pub(crate) struct Numbering {
75 numbers: BTreeMap<NodeId, u32>,
76}
77
78impl Numbering {
79 pub(crate) fn of(book: &Book, styles: &StyleTree) -> Numbering {
82 let mut numbering = Numbering::default();
83 let mut next = 1;
84 for section in &book.sections {
85 numbering.restart(&mut next, styles.style(section.id));
86 numbering.blocks(§ion.blocks, styles, &mut next);
87 }
88 numbering
89 }
90
91 pub(crate) fn on_pages(&self, pages: &BTreeMap<NodeId, u32>, start: u32) -> Numbering {
95 let mut numbers = BTreeMap::new();
96 let mut page = None;
97 let mut next = start;
98 for (node, at) in pages {
101 if page != Some(*at) {
102 page = Some(*at);
103 next = start;
104 }
105 numbers.insert(*node, next);
106 next += 1;
107 }
108 Numbering { numbers }
109 }
110
111 pub(crate) fn number(&self, node: NodeId) -> u32 {
114 self.numbers.get(&node).copied().unwrap_or(1)
115 }
116
117 fn blocks(&mut self, blocks: &[Block], styles: &StyleTree, next: &mut u32) {
118 for block in blocks {
119 self.restart(next, styles.style(block_id(block)));
120 match block {
121 Block::Heading { inlines, .. } | Block::Paragraph { inlines, .. } => {
122 self.inlines(inlines, styles, next)
123 }
124 Block::Blockquote { blocks, .. } => self.blocks(blocks, styles, next),
125 Block::List { items, .. } => {
126 for item in items {
127 self.restart(next, styles.style(item.id));
128 self.blocks(&item.blocks, styles, next);
129 }
130 }
131 Block::Table { head, body, .. } => {
132 for blocks in cell_blocks(head, body) {
133 self.blocks(blocks, styles, next);
134 }
135 }
136 Block::CodeBlock { .. }
137 | Block::ThematicBreak { .. }
138 | Block::PageBreak { .. }
139 | Block::ColumnBreak { .. }
140 | Block::Image { .. } => {}
141 }
142 }
143 }
144
145 fn inlines(&mut self, inlines: &[Inline], styles: &StyleTree, next: &mut u32) {
148 for note in notes_in_inlines(inlines) {
149 let Inline::Note { id, blocks, .. } = note else {
150 continue;
151 };
152 self.numbers.insert(*id, *next);
153 *next += 1;
154 self.blocks(blocks, styles, next);
155 }
156 }
157
158 fn restart(&mut self, next: &mut u32, style: &ComputedStyle) {
159 if let Some(number) = style.note_reset {
160 *next = number;
161 }
162 }
163}
164
165impl StyleTree {
166 pub(crate) fn numbers_notes_per_page(&self) -> bool {
170 self.style(self.notes_area()).note_reset.is_some()
171 }
172
173 pub(crate) fn first_note_number(&self) -> u32 {
175 self.style(self.notes_area()).note_reset.unwrap_or(1)
176 }
177}
178
179impl Paginator<'_> {
180 pub(super) fn note_number(&self, node: NodeId) -> u32 {
182 self.notes.borrow().number(node)
183 }
184
185 pub(super) fn note(&self, note: &Inline, source: Option<&str>) -> Option<Arc<Note>> {
189 let Inline::Note {
190 id,
191 blocks,
192 position,
193 ..
194 } = note
195 else {
196 return None;
197 };
198 let number = self.note_number(*id);
199 let (x, measure) = self.note_measure();
200 let style = self.styles.style(*id).clone();
201 let mut builder = Builder::new(self, source);
202 let start = builder.open(*id, &style, &[], x, measure);
203 let (inner, narrowed) = style.content_box(x, measure);
204 builder.blocks(
205 children(self.styles, *id, blocks, *position),
206 inner,
207 narrowed,
208 );
209 if let Some(marker) = self.note_marker(&style, number, x, measure) {
210 builder.hang(start, marker);
211 }
212 builder.close(&style, start);
213 if builder
214 .fragments
215 .iter()
216 .any(|fragment| fragment.notes.is_some())
217 {
218 self.warn(
219 "A note was written inside another note. The note inside is left out.".to_string(),
220 None,
221 );
222 }
223 Some(Arc::new(Note {
224 node: *id,
225 number,
226 fragments: builder.fragments,
227 }))
228 }
229
230 pub(super) fn note_measure(&self) -> (f32, f32) {
232 self.area_style().content_box(0.0, self.note_width())
233 }
234
235 pub(super) fn note_width(&self) -> f32 {
238 self.styles.default_page().geometry.measure()
239 }
240
241 fn note_marker(
245 &self,
246 style: &ComputedStyle,
247 number: u32,
248 x: f32,
249 measure: f32,
250 ) -> Option<Marker> {
251 let text = style.list_style_type.marker(number)?;
252 let line = self.line_of(&text, &style.paragraph())?;
253 let (left, _) = style.content_box(x, measure);
254 let x = left - self.line_width(&line);
255 Some(Marker { line, x })
256 }
257
258 pub(super) fn area_style(&self) -> &ComputedStyle {
260 self.styles.style(self.styles.notes_area())
261 }
262
263 pub(crate) fn number(&self, numbering: Numbering) {
267 *self.notes.borrow_mut() = numbering;
268 }
269}
270
271pub(super) struct Area {
274 pub(super) top: f32,
276 pub(super) height: f32,
278 pub(super) placed: Vec<(f32, Arc<Note>, usize)>,
282 pub(super) left: Vec<(Arc<Note>, usize)>,
285}
286
287pub(super) fn area_edges(style: &ComputedStyle) -> (f32, f32) {
289 let border = style.border.widths();
290 (
291 style.margin.top + border.top + style.padding.top,
292 style.margin.bottom + border.bottom + style.padding.bottom,
293 )
294}
295
296impl Paginator<'_> {
297 pub(super) fn area(
306 &self,
307 notes: &[(Arc<Note>, usize)],
308 foot: f32,
309 height: f32,
310 ) -> Option<Area> {
311 if notes.is_empty() {
312 return None;
313 }
314 let style = self.area_style();
315 let (above, below) = area_edges(style);
316 let room = height - foot - above - below;
317 let mut placed: Vec<(f32, Arc<Note>, usize)> = Vec::new();
318 let mut cursor = 0.0f32;
319 let mut owed: Vec<(Arc<Note>, usize)> = Vec::new();
320 for (note, from) in notes {
321 if !owed.is_empty() {
322 owed.push((note.clone(), *from));
323 continue;
324 }
325 let mut at = *from;
326 while at < note.fragments.len() {
327 let step = note.step(at, !placed.is_empty());
328 if cursor + step > room && !placed.is_empty() {
332 break;
333 }
334 cursor += step;
335 placed.push((cursor - note.fragments[at].height, note.clone(), at));
336 at += 1;
337 }
338 if at < note.fragments.len() {
339 owed.push((note.clone(), at));
340 }
341 }
342 if placed.is_empty() {
343 return Some(Area {
344 top: height,
345 height: 0.0,
346 placed,
347 left: owed,
348 });
349 }
350 let outer = above + cursor + below;
351 Some(Area {
352 top: (height - outer).max(foot),
353 height: outer,
354 placed,
355 left: owed,
356 })
357 }
358
359 pub(super) fn area_items(
363 &self,
364 area: &Area,
365 origin: (f32, f32),
366 ) -> (Vec<DrawItem>, Vec<(NodeId, PageBox)>) {
367 let style = self.area_style();
368 let (above, _) = area_edges(style);
369 let (x, _) = self.note_measure();
370 let (left, width) = style.border_box(0.0, self.note_width());
371 let top = area.top + style.margin.top;
372 let height = (area.height - style.margin.top - style.margin.bottom).max(0.0);
373 let ink = |edge: crate::style::Border| edge.color.unwrap_or(style.color);
374 let mut items = super::flow::box_items(
375 origin.0 + left,
376 origin.1 + top,
377 width,
378 height,
379 style.border_radius.resolve(width, height),
380 style.border.widths(),
381 crate::style::Edges {
382 top: ink(style.border.top),
383 right: ink(style.border.right),
384 bottom: ink(style.border.bottom),
385 left: ink(style.border.left),
386 },
387 &self.backdrop(&style.background),
388 style.z_index,
389 );
390 let inner = (origin.0 + x, origin.1 + area.top + above);
391 let placed: Vec<(f32, &Fragment)> = area
392 .placed
393 .iter()
394 .map(|(at, note, index)| (*at, ¬e.fragments[*index]))
395 .collect();
396 let (mut boxes, mut areas) = decorate(&placed);
397 super::flow::shift(&mut boxes, inner.0, inner.1);
398 super::flow::shift_boxes(&mut areas, inner.0, inner.1);
399 items.append(&mut boxes);
400 for (at, fragment) in placed {
401 items.append(&mut self.fragment_items(fragment, inner.0, inner.1 + at));
402 }
403 (items, areas)
404 }
405}
406
407impl Flow<'_, '_> {
408 pub(super) fn room(&self, fragment: &Fragment) -> f32 {
417 let coming = fragment.notes.as_deref().map(Vec::as_slice).unwrap_or(&[]);
418 let owed = self.owed(self.column);
419 if owed.is_empty() && coming.is_empty() {
420 return self.height;
421 }
422 let (above, below) = area_edges(self.paginator.area_style());
423 let mut wanted = above + below;
424 for (index, (note, from)) in owed.iter().enumerate() {
425 wanted += note.height(*from, index > 0);
426 }
427 let under = !owed.is_empty();
428 for (index, note) in coming.iter().enumerate() {
429 wanted += note.height(0, under || index > 0);
430 }
431 (self.height - wanted).max(0.0)
432 }
433
434 fn owed(&self, column: u32) -> Vec<(Arc<Note>, usize)> {
437 self.notes
438 .iter()
439 .filter(|(at, _, _)| *at == column)
440 .map(|(_, note, from)| (note.clone(), *from))
441 .collect()
442 }
443
444 pub(super) fn notes_areas(&self, placed: &[Placed]) -> Vec<(u32, Area)> {
452 let mut areas = Vec::new();
453 let mut left: Vec<(Arc<Note>, usize)> = Vec::new();
454 for column in 0..self.columns.max(1) {
455 let mut owed = std::mem::take(&mut left);
456 owed.append(&mut self.owed(column));
457 if owed.is_empty() {
458 continue;
459 }
460 let foot = placed
461 .iter()
462 .filter(|placed| placed.column == column)
463 .map(|placed| placed.top + placed.height)
464 .fold(0.0, f32::max);
465 let Some(area) = self.paginator.area(&owed, foot, self.height) else {
466 continue;
467 };
468 left = area.left.clone();
469 areas.push((column, area));
470 }
471 areas
472 }
473
474 pub(super) fn notes_closed(&mut self, areas: &[(u32, Area)]) {
477 let page = self.pages.len() as u32;
478 for (_, note, from) in &self.notes {
479 if *from == 0 {
480 self.note_pages.insert(note.node, page);
481 }
482 }
483 self.notes = areas
484 .last()
485 .map(|(_, area)| area.left.clone())
486 .unwrap_or_default()
487 .into_iter()
488 .map(|(note, from)| (0, note, from))
489 .collect();
490 }
491}