1//! The reading view over OneNote-written pages: what it offers, the order it reads, and that
2//! the reflowed page keeps every paragraph and object while only the shown copy moves.
3
4use canvas::{
5 layout::TextEngine,
6 reading::{self, Kept, Kind, Refusal, Verdict},
7};
8use onestore::{
9 Arena, ExGuid, Section,
10 page::{Page, PageObject},
11};
12use std::collections::BTreeSet;
13
14const COLUMN: f32 = 230.0;
15
16fn first_page(bytes: &[u8]) -> Page {
17 let arena = Arena::default();
18 let mut section = Section::open(&arena, bytes.to_vec()).unwrap();
19 let space = section.pages().unwrap()[0].0;
20 section.page(space).unwrap()
21}
22
23fn paragraphs(page: &Page) -> BTreeSet<ExGuid> {
24 page.objects
25 .iter()
26 .filter_map(|object| match object {
27 PageObject::Outline(outline) => Some(outline.paragraphs.iter().map(|p| p.id)),
28 _ => None,
29 })
30 .flatten()
31 .collect()
32}
33
34#[test]
35fn a_planning_page_reads_down_one_column() {
36 let page = first_page(include_bytes!(
37 "../../../corpus/notebook-management/native/page-color/Garden.one"
38 ));
39 let mut engine = TextEngine::default();
40 let read = reading::read(&page, COLUMN, &mut engine).unwrap();
41 assert_eq!(
42 read.verdict,
43 Verdict::Partial(vec![Kept::Asides, Kept::SideBySide, Kept::Wide])
44 );
45 let reflowed = read.page.unwrap();
46 // Splitting around asides drops no paragraph; only spacing blank runs could go.
47 assert_eq!(paragraphs(&reflowed), paragraphs(&page));
48 // Every block starts at the column's left edge or an aside's indent, top to bottom.
49 let mut tops = Vec::new();
50 for block in &read.blocks {
51 let object = reflowed
52 .objects
53 .iter()
54 .find(|object| object.id() == block.members[0])
55 .unwrap();
56 let layout = object.layout();
57 if block.kind == Kind::Text {
58 assert!(layout.max_width.unwrap() <= COLUMN);
59 }
60 tops.push(layout.y.unwrap());
61 }
62 assert!(tops.windows(2).all(|pair| pair[0] < pair[1]), "{tops:?}");
63 // The page itself is untouched.
64 let again = first_page(include_bytes!(
65 "../../../corpus/notebook-management/native/page-color/Garden.one"
66 ));
67 assert_eq!(
68 serde_json::to_string(&page).unwrap(),
69 serde_json::to_string(&again).unwrap()
70 );
71}
72
73#[test]
74fn a_drawing_is_not_reflowed() {
75 let page = first_page(include_bytes!(
76 "../../../corpus/ink-edit/drawing/candidate/ink.one"
77 ));
78 let read = reading::read(&page, COLUMN, &mut TextEngine::default()).unwrap();
79 assert_eq!(read.verdict, Verdict::Refused(Refusal::Drawn));
80 assert!(read.page.is_none());
81}
82
83#[test]
84fn a_page_as_narrow_as_the_column_shows_as_laid_out() {
85 let page = first_page(include_bytes!(
86 "../../../corpus/append/round-01/complex/notebook/synthetic.one"
87 ));
88 let read = reading::read(&page, 2000.0, &mut TextEngine::default()).unwrap();
89 assert_eq!(read.verdict, Verdict::Fits);
90}