1# The page: editor and canvas
2
3A OneNote page is a free canvas, but it doesn't feel like a drawing app. You
4click anywhere and type, and a text box (an *outline*) appears and grows as you
5write. Outlines wrap, lists indent, tags hang in the margin. `canvas` is the
6crate that makes a page behave that way and look the way OneNote 2010 draws
7it. It depends on `onestore`'s page model and on `draw`. It knows nothing
8about storage, windows or the interface kit, which is why the same page runs
9inside the desktop app and inside a UIKit view on iOS.
10
11## Layers
12
13```text
14onestore::page::Page stored identities, formatting, unknown content kept aside
15 │
16canvas::document text outlines as paragraphs of rich text, UTF-16 positions
17canvas::editor CanvasEditor: edits, selection, composition, undo, the ops each edit lowers to
18canvas::layout, outline shaping (parley), Windows line metrics, outline and table geometry
19 │
20canvas::gpu::page PageScene: the page as draw primitives; pictures decoded off-thread
21canvas::interaction PageView: hit layers, drags, grid, handles, key routing, scroll, zoom, AccessKit
22 │
23host translates platform events in; carries out the Requests that come back
24```
25
26A host feeds `PageView` pointer, key and text-input events. It gets back a
27`Response` saying whether the page, the selection or only the view changed,
28plus the occasional `Request` the page can't do itself: show a date picker,
29read the clipboard, open a link. Everything platform-specific stays on the
30host's side of that line, shortcuts included: the page takes editing keys, and
31the host's command table runs the chords for formatting, tags, zoom and the
32clipboard through the page's own methods.
33
34## Editing emits ops
35
36`CanvasEditor` holds the working page. When an edit changes what's stored, the
37editor records the `onestore::op`s the change lowers to at that moment. The
38host collects them and hands them to the section as one `Edit`. No page is
39ever rebuilt or diffed to be saved, so the work of saving a keystroke follows
40the size of the edit, not the size of the page.
41
42Undo lives in the editor, not in storage. Each history entry keeps the inverse
43of the change it made. Undoing applies that inverse and emits its ops as a new
44edit, so the file only ever moves forward, like OneNote's. Undo steps are
45OneNote 2010's too: typing and backspaces at one caret are a single step until
46the caret moves or another kind of edit comes between, though each keystroke's
47ops still reach storage as it is typed. Undoing a deletion
48brings back the original identities, so internal links to those paragraphs
49survive an undo.
50
51Each page keeps its history while the window is open, as in OneNote 2010: the
52desktop app parks a page's editor when it is left and takes it up again, through
53the same reload in place, when the page opens. Between those edits the app keeps
54what was done to pages and sections (new, deleted, moved and indented pages, page
55and section names, sections moved), and Undo takes back whichever came last: the
56open page's own step, or the last such action in its section or notebook,
57showing the page it changes. Unlike OneNote, an edit doesn't end what actions Undo
58can reach, so New Page, a typed title, Undo, Undo takes the title and then the
59page. Each step back is computed against the section as it is then, one edit of
60its own; a step whose page is gone, or holds work it didn't make, is passed over.
61
62Input-method composition (marked text) stays inside the editor until it
63commits, and only then becomes ops. When another client changes the open page,
64the editor compares the stored page with what it last read plus the ops it has
65handed out, and reloads in place.
66
67## OneNote-faithful geometry
68
69The goal is that a page looks the same in Snowbound as in OneNote: same wraps,
70same line heights, same places. That took measuring, not guessing.
71
72- **Stored geometry is not laid-out geometry.** An outline's stored width and
73 height are constraints and hints. The displayed box comes from layout, so the
74 canvas lays out as OneNote does and never treats a stored size as a clip.
75- **Line boxes use Windows metrics.** OneNote measures lines with a font's
76 Windows ascent and descent, not the typographic or horizontal-header values
77 most text stacks pick. The difference is small per line and large per page.
78 Drawing and hit-testing share these line boxes.
79- **Substitutes match metrics.** Where the system lacks Calibri, Arial, Times
80 New Roman or Courier New, bundled metric-compatible substitutes (Carlito,
81 Arimo, Tinos, Cousine) stand in, under the stored font name.
82- **OneNote's constants are OneNote's.** New outlines take OneNote's default
83 width. Dragging snaps to its grid, anchored at the page's margin origin, unless
84 Snap To Grid (the shape gallery's last item, kept between launches) is off. Tags
85 sit in a column to the left of the text with OneNote's spacing, and a tag's
86 colour paints the whole paragraph as it does there.
87- **A right-to-left page is the same frame, seen from its right.** OneNote 2010
88 keeps its positions left to right like any page's, from a margin origin some
89 10,800 pt out, and opens it scrolled to the right end of its content, keeping
90 that edge as the window resizes. The canvas does the same and stores clicks,
91 strokes and drags as on any page (`corpus/rtl-page`).
92
93These rules were established against OneNote's own output: its XML export
94gives outline sizes, its PDF export gives exact line breaks, and screenshots
95give placement. The comparators in `tools/canvas` (with the probes
96`layout-probe` and `page-probe`) keep checking them.
97
98Equations draw in two dimensions from the tree `onestore::page::Math` parses,
99each in a space kept in its line of text, so text and links around them keep
100their look and the line grows to hold them. They are edited as OneNote's equation editor edits them: Alt+= starts one,
101typing is its linear format (UnicodeMath), and a space builds up what it ends.
102Linear and Professional switch an equation between the forms, and OneNote
103stores both. Links follow OneNote too: a typed URL links itself when a space or
104Enter ends it, the Link dialog stores its address in a hidden field code before
105the label, and a click or Enter opens a link. URL text shows as a link, as
106OneNote links it when it opens a page, without being stored as one. Ink draws stroke by stroke in page
107coordinates. Page templates' background art is recreated as vector art and
108recognised by the stored picture's hash. OneNote's bitmaps aren't shipped.
109
110## Attached files
111
112A file sits in an outline's flow as OneNote draws it: its icon over its name,
113extension hidden, in a 54-point column. Attaching splits the caret's paragraph
114around the file, and the text after the caret follows it with the caret, as
115OneNote 2010 attaches and drops files. Every new file stores the icon OneNote
116stores beside it, because OneNote draws a broken picture for a file without
117one: the host's system icon where it has one, the canvas's blank page
118otherwise. A double click or the context menu's Open asks the host to open a
119copy; Save As writes the bytes where the user chooses.
120
121Attached or dropped where a click on blank page left the caret, the file goes
122on the page itself, as OneNote 2010 places it: the same column at the caret's
123grid point, outside any outline. It selects, drags on the grid, deletes and
124moves with Insert Space as a picture does, and opens and saves as above.
125
126A tag on a picture or file is stored on the object itself, as OneNote 2010 stores
127the tag Ctrl+1 gives a selected one, and drawn in a column left of it, centred on
128it; a click checks its box (`corpus/object-tags`). A picture's link follows on
129Ctrl+click, Command+click on macOS, while a click selects it, as OneNote's
130tooltip says (`corpus/picture-link`).
131
132OneNote 2010's Ctrl+1 leaves a bulleted or numbered paragraph's list beside its
133new To Do box, and it has no command that converts a list. Make To-Do List, in
134the page's context menu and the palette, trades the selected paragraphs' bullets
135and numbers for the first check box tag in the user's list as one undo step;
136Make Bulleted List trades the tag back for a bullet (`corpus/to-do-list`).
137OneNote's Enter never carries a tag, and on an empty tagged paragraph it opens a
138plain one above (`corpus/structural-probe`). Snowbound's Enter continues a to-do
139list as a list continues: the new paragraph takes an unchecked copy of each check
140box, and Enter on an empty item drops them.
141
142An outline holding only pictures or files takes a paragraph after them where a
143click beside them lands, as OneNote 2010 adds one when typing there. It is
144stored with the first edit that reaches it, and undoing back to it empty takes it
145out again (`corpus/object-outline`).
146
147A file printout's pages are pictures whose stored data is the printout's XPS
148package. The page draws the PNG OneNote rendered of each
149(WebPictureContainer14), framed in grey as OneNote frames them, and moves them as
150pictures. A printout page deleted and brought back by undo returns as the page it
151was: its XPS package, the PNG and the properties tying it to the printout, written
152back as read (`corpus/printout`).
153
154Pictures go in as OneNote 2010 pastes and inserts them. At a caret in text the
155paragraph splits around the picture, as around a file. On blank page the picture
156lies on the page at the caret, and the caret moves to the grid row below it.
157From the title it joins the outline where the body starts, or lies two grid rows
158below the page's content when none starts there. A picture takes the size its
159resolution gives it, or 96 dpi without one. Paste takes files first (a picture
160file as its picture, as a dropped one goes in), then Snowbound's own copy, then
161a web page, its formatted text, lists, tables and pictures in order as one undo
162step, then text, then a picture: Finder offers a copied file's name and icon
163beside it, and other apps a picture of copied text.
164
165Copy offers what OneNote 2010 does beside text, HTML with each run's formatting
166inline, lists as `ul` and `ol` and tables bordered, which OneNote and Word paste
167as copied (`corpus/clipboard`). Snowbound's own format, a `Clip` of paragraphs
168and the definitions they name as JSON, carries styles, tags and pictures too.
169Several paragraphs go between the halves of the caret's paragraph, an empty
170half dropped; a title takes the text alone.
171
172## Recordings
173
174Record Audio and Record Video work as OneNote 2010's do. The caret's paragraph
175splits around a line saying when recording started, in OneNote's grey `cite`
176style, and the caret goes on below it. Text written while recording links to
177the moment it was written; text written while paused links to nothing, and the
178pause is left out of later moments. On Stop, the file goes in above that line,
179named after the page. Hovering a linked note or a recording shows OneNote's blue
180play button in the margin, and a click asks the host to play from five seconds
181before that moment, OneNote's default rewind. While a recording plays, See
182Playback highlights the note linked last at or before the moment playing,
183scrolling it into view when it changes.
184
185The host records audio as 16 kHz WAV and stores it as IMA ADPCM, and video as
186AVI of Motion JPEG at 320 by 240 and 15 pictures a second with PCM sound, both
187of which OneNote plays (`corpus/recording/video`); `canvas::recording` makes both,
188so every host stores the same bytes. GStreamer writes that AVI
189directly; on macOS a capture session records a movie that `AVAssetReader` reads
190back into it off the main thread after Stop, the transport saying so and the page
191editable meanwhile. Mac OS X 10.6, without AVFoundation, opens recordings in the
192system's player and does not record. Snowbound plays both itself: the sound through the platform's
193player, decoded from IMA ADPCM first, and a video's pictures in the transport
194over the page, which also carries OneNote's Pause, Stop, ten-second and
195ten-minute skips, Seek To and See Playback.
196
197## Drawing
198
199The Draw tab's tools work as OneNote 2010's do with a mouse (`corpus/ink-tools`).
200Every stroke and every shape is a drawing of its own, added on top of the page
201when the pen lifts: one edit and one undo step, published as one appended
202revision, or in one with the strokes queued behind it during a sync round trip,
203as keystrokes are. Shapes are ink too. Their corners snap to the placement grid, and the
204drawing keeps the shape's kind and anchors beside its strokes, which OneNote
205edits it by. A highlighter's rectangular tip multiplies what lies beneath, so
206text under it stays dark. The stroke eraser takes whole drawings, or only the
207strokes it touches in an older drawing of several. The lasso picks the drawings
208with most of their points inside it. They move by their offset, as OneNote
209moves ink, and Delete removes them. Escape returns to Select & Type, where a
210click on ink picks it. The default pen draws in the open section's accent at
211the light theme's shade, so a stroke stores one real colour and shows it in both
212themes.
213
214A pen that reports pressure (a tablet on macOS, the Apple Pencil) draws and stores it as
215OneNote 2010 does with pressure sensitivity on: each point's width is the pen's times
2160.25 plus 1.5 times the pressure, and the stroke keeps NormalPressure beside X and Y
217(`corpus/ink-pressure`). A mouse, trackpad or finger draws at the pen's width, and so
218does every pen with OneNote's "Use pen pressure sensitivity" turned off (Options >
219Advanced on the desktop, the pen's colour menu on iOS; on by default). winit reports no
220tablet pressure on Linux.
221
222## Tables and selections across them
223
224Columns size as OneNote 2010 sizes them (`corpus/table-widths`). An unlocked
225column fits its widest line plus 4.347 pt, never under a new column's 37.11 pt,
226widening and narrowing with each edit, which stores the width in the same
227revision as its text. A table stops at the outline's width and its cells wrap
228from there. Dragging a column's right border resizes that column alone, the
229columns after it moving with it, down to 37.11 pt; on release it is one edit
230and one undo step, and the column is locked, so typing no longer fits it.
231
232Note tags on a table sit in the tag column centred on it, and a click checks its
233box (`corpus/table-tags`). A selection crossing a table's edge deletes as
234OneNote 2010 deletes one: nothing joins across the edge, cells inside are
235emptied, and where the selection runs on past the table its rows inside go, the
236table with them when all do. What replaces the selection goes in at its start
237(`corpus/cross-container`). Tab and Link leave such a selection alone, and
238Shift+Enter a caret inside a link, as OneNote's do; Alt+= across paragraphs
239makes each paragraph's part an equation, and a deletion between two equations
240joins them where neither seam lies inside an object (`corpus/equation-join`).
241An edit replacing a selection with an end inside an equation's object (a
242fraction, a script, a root) takes the whole object first, as OneNote's equation
243editor selects, and across paragraphs an object so taken at its paragraph's end
244takes that end too; a placeholder ("Type equation here.") is taken whole
245(`corpus/equation-select`).
246
247## Styles and themes
248
249The Styles gallery is OneNote 2010's: Heading 1 to 6, Page Title, Citation, Quote, Code
250and Normal, stored under OneNote's names (`h1`, `PageTitle`, `cite`, `blockquote`, `code`,
251`p`). Applying one gives the paragraph the page's style object of that definition and
252clears its character formatting but links, fields and language, as OneNote's does; Enter
253at a paragraph's end takes its style's NextStyle, so a heading is followed by Normal.
254Ctrl+Alt+1 to 6 apply the headings, and Clear Formatting at a caret applies Normal.
255
256A theme gives the eleven styles a look, and a page wears it as its style objects: OneNote
257draws a page by its own style objects, so OneNote users see the theme under the same
258names. Changing a theme moves each styled paragraph to a new style object of the same name
259(style objects are read-only) in one revision per page, and a page is brought to its
260theme when it opens, so a notebook-wide change costs each page only when someone looks at
261it. Which theme a notebook, section or page wears lives in the notebook's `.snowbound`
262folder, beside the tags' art (`corpus/styles`).
263
264## Content the editor doesn't understand
265
266Nothing is lost for being unfamiliar. A paragraph the canvas can't draw
267becomes a labelled placeholder that keeps its place in the flow, and the rest
268of its outline stays editable. An object the editor can't hold draws as stored
269and stays read-only. Its bytes are never touched either way. Wherever a
270remaining "can't edit this" state exists, the aim is to remove it by teaching
271the editor the structure, not by flattening the content.
272
273## Pictures and memory
274
275The page scene reads only picture headers when it's built. Pictures in and
276near the view decode on a background thread at the size they're shown, within
277a fixed memory budget, and pictures long out of view are let go. No number or
278size of pictures can make a page fail to open. Opening a page happens on its
279own thread too. The current page stays live until the new one is laid out and
280the pictures it shows first are ready.
281
282## Accessibility
283
284The page builds an AccessKit tree. Each text outline appears as its own
285editable text area, whose runs carry the canvas's real line boxes and
286character positions, so a screen reader's caret and selection land where the
287eye does. Native selection and replacement actions go through the editor's
288history like any other edit. The tree updates only while an assistive client
289is listening, and never for a caret blink. The interface's own tree holds it at
290the page's box (see [the interface kit](ui.md#accessibility-and-the-keyboard)).
291
292## Spelling
293
294Spelling is checked as OneNote 2010 checks it with its default proofing
295options. Words in capitals, words with digits, and Internet and file addresses
296go unchecked, and a word repeating the one before it is marked as repeated.
297Each run is checked in the language it stores, so a French paragraph takes the
298French dictionary and an equation none. The host supplies the dictionary;
299`canvas::spelling` checks each paragraph on a thread of its own when it first
300comes into view, and keeps the result by the paragraph's text, so drawing never
301waits on it. Marked words carry OneNote's red zigzag, one pixel thick at any
302zoom and laid on the device's pixel grid so a 1× screen shows OneNote's exact
303pixels, except the word still being typed. The context menu (the edit menu on
304iOS) offers the dictionary's corrections, Ignore and Add to Dictionary, and the
305Spelling pane (F7) walks the page's marked words. A correction is an ordinary
306edit, one revision. Nothing about spelling is stored in the page.
307
308## Printing and PDF
309
310`canvas::print` lays pages on paper as OneNote 2010 prints them (`corpus/print`): between
311half-inch top and bottom margins with the margin origin an inch in, the whole page shrunk
312when its content reaches past the paper's right edge, and each sheet after the first
313starting at the line of text or picture the one before would have cut. Rule lines and
314template art print across the paper; the page colour does not. The footer names the
315section and numbers the sheets. `draw::pdf` writes the same primitives the screen paints
316as PDF: text in subset fonts whose ToUnicode maps come from the laid-out text, so it
317selects and searches, ligatures included; ink and shapes as paths; pictures and tag
318icons as images. On the desktop, Print and Export as PDF first show OneNote's Print Preview
319and Settings, less the preview: the range (page, page group, section, and for a PDF the
320notebook), paper, orientation, fitting to the paper's width and the footer. Print then hands
321the PDF to AppKit's print panel, the XDG print portal or the shell's print verb for PDFs.
322On iOS the page menu prints the page through the print sheet or shares its PDF.
323
324## Search, dates, conflicts
325
326Smaller modules follow the same pattern of reproducing OneNote's behaviour
327precisely. `search` matches the way OneNote 2010 searches: word prefixes,
328ignoring case and diacritics, title matches first, and the text OneNote recognised
329in pictures, which it stores in them, as OneNote's search finds it. `date` edits the title's
330date and time fields the way OneNote stores a changed page date. `conflict`
331shows conflict pages with OneNote's highlight.