From 9da8af01dee9dec5df91b1f0832d6298c8f11e4d Mon Sep 17 00:00:00 2001 From: clover caruso Date: Wed, 30 Sep 2026 14:43:26 -0700 Subject: [PATCH] feat: hybrid macOS icon, Intel Mac build, older systems, appearance setting, image paste, pinch zoom, guide draft - macOS ships a prebuilt Assets.car (Xcode 26.0.1) so Tahoe and later show the Liquid Glass icon and earlier systems the Sequoia icon; iOS uses the same Icon Composer icon. - An Intel Mac build (10.13+), the Apple silicon build on macOS 11+ with the macOS 14-only calls gated, and Linux builds against glibc 2.17. - Appearance: System, Light, or Dark independent of the OS, on every platform; Dark Pages is now Pages Match UI Theme. - Pasting pictures (#51) as OneNote 2010 places and sizes them; pinch zoom keeps the point under the cursor (#52). - The Snowbound Guide notebook draft, not offered in the app until reviewed. - Windows polish, options and content work in progress that compiles and passes. Assisted-by: claude-opus-5.5 --- Cargo.lock | 47 +- apps/ios/Snowbound.xcodeproj/project.pbxproj | 12 +- apps/ios/Snowbound/App.swift | 27 + apps/ios/Snowbound/CanvasView.swift | 35 +- apps/ios/Snowbound/Lists.swift | 36 +- apps/ios/Snowbound/Notebooks.swift | 4 + apps/ios/Snowbound/PageViewController.swift | 24 +- arc/canvas.md | 21 + corpus/equation-select/README.md | 26 + .../candidate/Open Notebook.onetoc2 | Bin 0 -> 1604 bytes corpus/equation-select/candidate/links.one | Bin 0 -> 46824 bytes corpus/equation-select/cold/commands.jsonl | 3 + corpus/equation-select/cold/machine.json | 1 + .../cold/notebook/Open Notebook.onetoc2 | Bin 0 -> 3764 bytes .../equation-select/cold/notebook/links.one | Bin 0 -> 46824 bytes .../cold/read/environment.json | 7 + .../equation-select/cold/read/hierarchy.xml | 2 + .../cold/read/page-000.navigation.json | 13 + corpus/equation-select/cold/read/page-000.png | Bin 0 -> 45260 bytes corpus/equation-select/cold/read/page-000.xml | 5 + .../equation-select/cold/read/payloads.json | 3 + corpus/equation-select/cold/run.json | 18 + corpus/equation-select/cold/scripts/cold.ps1 | 27 + corpus/equation-select/cold/scripts/read.ps1 | 144 +++ corpus/equation-select/cold/source.json | 14 + corpus/equation-select/cold/teardown.json | 1 + corpus/equation-select/lab/after.xml | 5 + corpus/equation-select/lab/before.xml | 3 + corpus/equation-select/lab/limit-enter.xml | 5 + .../equation-select/lab/placeholder-enter.xml | 5 + corpus/equation-select/lab/roots-deleted.xml | 3 + corpus/print/README.md | 33 + corpus/print/native/Print.one | Bin 0 -> 47496 bytes corpus/print/native/rules-section.pdf | Bin 0 -> 145613 bytes corpus/print/native/section.pdf | Bin 0 -> 168568 bytes crates/canvas/Cargo.toml | 7 + crates/canvas/examples/print_pdf.rs | 40 + crates/canvas/examples/scratch_eqref.rs | 667 +++++++++++ crates/canvas/examples/scratch_files.rs | 15 + crates/canvas/examples/scratch_runs.rs | 23 + crates/canvas/src/editor.rs | 67 +- crates/canvas/src/editor/equation.rs | 122 +- crates/canvas/src/editor/table.rs | 1 + crates/canvas/src/gpu/mod.rs | 1 + crates/canvas/src/gpu/page.rs | 85 ++ crates/canvas/src/interaction/ink.rs | 10 +- crates/canvas/src/interaction/mod.rs | 74 +- crates/canvas/src/interaction/tests.rs | 37 +- crates/canvas/src/layout.rs | 3 + crates/canvas/src/lib.rs | 2 + crates/canvas/src/print.rs | 553 +++++++++ crates/canvas/tests/links_equations.rs | 187 +++ crates/canvas/tests/picture_paste.rs | 196 ++++ crates/draw/Cargo.toml | 5 + crates/draw/src/render.rs | 5 + crates/draw/src/render/pdf.rs | 1004 +++++++++++++++++ crates/draw/src/render/text.rs | 25 +- crates/mobile/src/lib.rs | 26 +- crates/mobile/src/tests.rs | 2 +- crates/notebook/Cargo.toml | 3 + crates/notebook/src/lib.rs | 3 +- crates/notebook/src/session.rs | 28 +- crates/onestore/examples/opts29_dump.rs | 29 + crates/snowbound/Cargo.toml | 6 +- crates/snowbound/assets/icon/Assets.car | Bin 0 -> 36936 bytes crates/snowbound/assets/icon/README.md | 20 + crates/snowbound/linux/README.md | 4 +- crates/snowbound/linux/package.sh | 6 +- crates/snowbound/src/commands.rs | 80 +- crates/snowbound/src/desktop_linux.rs | 11 +- crates/snowbound/src/guide.rs | 106 ++ crates/snowbound/src/linux.rs | 46 +- crates/snowbound/src/macos.rs | 82 +- crates/snowbound/src/main.rs | 143 ++- crates/snowbound/src/manage.rs | 88 +- crates/snowbound/src/media_macos.rs | 9 +- crates/snowbound/src/menubar.rs | 7 +- crates/snowbound/src/options.rs | 16 +- crates/snowbound/src/paste.rs | 184 +++ crates/snowbound/src/print.rs | 118 ++ crates/snowbound/src/print_linux.rs | 110 ++ crates/snowbound/src/print_macos.rs | 153 +++ crates/snowbound/src/print_windows.rs | 61 + crates/snowbound/src/screenshot.rs | 4 +- .../snowbound/src/screenshot/snow_leopard.rs | 32 +- crates/snowbound/src/settings.rs | 44 +- crates/snowbound/src/sidebar.rs | 8 +- crates/snowbound/src/update.rs | 30 +- crates/snowbound/src/windows.rs | 67 +- crates/ui/src/layout.rs | 34 + crates/ui/src/lib.rs | 7 + crates/ui/src/tests.rs | 11 + crates/ui/src/text.rs | 1 + .../Snowbound Guide/.snowbound/tags.json | 8 + ...978ff3f1e5f696601ca46fed3803a81c37792c.svg | 14 + .../Snowbound Guide/Drawing & Recording.one | Bin 0 -> 92072 bytes .../Snowbound Guide/Getting Started.one | Bin 0 -> 89664 bytes .../Snowbound Guide/Open Notebook.onetoc2 | Bin 0 -> 6008 bytes .../Snowbound Guide/Sharing & Sync.one | Bin 0 -> 26976 bytes .../Snowbound Guide/Tags & Search.one | Bin 0 -> 35864 bytes .../Snowbound Guide/Writing & Formatting.one | Bin 0 -> 86896 bytes platform/snow-leopard/rt/appkit.c | 8 - tools/RELEASE.md | 37 +- tools/canvas/README.md | 2 +- tools/canvas/build_macos.py | 21 +- tools/native/picture-objects.ps1 | 37 + tools/native_runner.py | 2 +- tools/release.py | 8 +- tools/test_equation_select.py | 40 + tools/test_release.py | 7 +- 110 files changed, 5106 insertions(+), 310 deletions(-) create mode 100644 corpus/equation-select/README.md create mode 100644 corpus/equation-select/candidate/Open Notebook.onetoc2 create mode 100644 corpus/equation-select/candidate/links.one create mode 100644 corpus/equation-select/cold/commands.jsonl create mode 100644 corpus/equation-select/cold/machine.json create mode 100644 corpus/equation-select/cold/notebook/Open Notebook.onetoc2 create mode 100644 corpus/equation-select/cold/notebook/links.one create mode 100644 corpus/equation-select/cold/read/environment.json create mode 100644 corpus/equation-select/cold/read/hierarchy.xml create mode 100644 corpus/equation-select/cold/read/page-000.navigation.json create mode 100644 corpus/equation-select/cold/read/page-000.png create mode 100644 corpus/equation-select/cold/read/page-000.xml create mode 100644 corpus/equation-select/cold/read/payloads.json create mode 100644 corpus/equation-select/cold/run.json create mode 100644 corpus/equation-select/cold/scripts/cold.ps1 create mode 100644 corpus/equation-select/cold/scripts/read.ps1 create mode 100644 corpus/equation-select/cold/source.json create mode 100644 corpus/equation-select/cold/teardown.json create mode 100644 corpus/equation-select/lab/after.xml create mode 100644 corpus/equation-select/lab/before.xml create mode 100644 corpus/equation-select/lab/limit-enter.xml create mode 100644 corpus/equation-select/lab/placeholder-enter.xml create mode 100644 corpus/equation-select/lab/roots-deleted.xml create mode 100644 corpus/print/README.md create mode 100644 corpus/print/native/Print.one create mode 100644 corpus/print/native/rules-section.pdf create mode 100644 corpus/print/native/section.pdf create mode 100644 crates/canvas/examples/print_pdf.rs create mode 100644 crates/canvas/examples/scratch_eqref.rs create mode 100644 crates/canvas/examples/scratch_files.rs create mode 100644 crates/canvas/examples/scratch_runs.rs create mode 100644 crates/canvas/src/print.rs create mode 100644 crates/canvas/tests/picture_paste.rs create mode 100644 crates/draw/src/render/pdf.rs create mode 100644 crates/onestore/examples/opts29_dump.rs create mode 100644 crates/snowbound/assets/icon/Assets.car create mode 100644 crates/snowbound/assets/icon/README.md create mode 100644 crates/snowbound/src/guide.rs create mode 100644 crates/snowbound/src/paste.rs create mode 100644 crates/snowbound/src/print.rs create mode 100644 crates/snowbound/src/print_linux.rs create mode 100644 crates/snowbound/src/print_macos.rs create mode 100644 crates/snowbound/src/print_windows.rs create mode 100644 docs/guide-notebook/Snowbound Guide/.snowbound/tags.json create mode 100644 docs/guide-notebook/Snowbound Guide/.snowbound/tags/308029094b76e765ca4025c6e8978ff3f1e5f696601ca46fed3803a81c37792c.svg create mode 100644 docs/guide-notebook/Snowbound Guide/Drawing & Recording.one create mode 100644 docs/guide-notebook/Snowbound Guide/Getting Started.one create mode 100644 docs/guide-notebook/Snowbound Guide/Open Notebook.onetoc2 create mode 100644 docs/guide-notebook/Snowbound Guide/Sharing & Sync.one create mode 100644 docs/guide-notebook/Snowbound Guide/Tags & Search.one create mode 100644 docs/guide-notebook/Snowbound Guide/Writing & Formatting.one create mode 100644 tools/native/picture-objects.ps1 create mode 100644 tools/test_equation_select.py diff --git a/Cargo.lock b/Cargo.lock index b6a15291fdcbdb831ac12c18250d3d85c26e70cb..e20e679dbdee903dedff8325f5612f9c093525ea 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -228,9 +228,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0348a1c054491f4bfe6ab86a7b6ab1e44e45d899005de92f58b3df180b36ddaf" dependencies = [ "clipboard-win", + "image", "log", "objc2 0.6.4", "objc2-app-kit 0.3.2", + "objc2-core-foundation", + "objc2-core-graphics", "objc2-foundation 0.3.2", "parking_lot", "percent-encoding", @@ -633,6 +636,7 @@ dependencies = [ "draw", "icu_normalizer", "image", + "miniz_oxide 0.8.9", "onestore", "parley", "png", @@ -974,10 +978,13 @@ dependencies = [ "bytemuck", "image", "linebender_resource_handle", + "miniz_oxide 0.8.9", "parley", + "pdf-writer", "png", "pollster", "roxmltree", + "subsetter", "swash", "wgpu", ] @@ -1971,7 +1978,7 @@ dependencies = [ "naga-types", "num-traits", "once_cell", - "rustc-hash", + "rustc-hash 1.1.0", "spirv", "thiserror 2.0.20", "unicode-ident", @@ -1985,7 +1992,7 @@ checksum = "590afbf58a6f4f62873cd5cff4468061844bafa1cdf399cc954537c22d768d49" dependencies = [ "hashbrown 0.17.1", "indexmap", - "rustc-hash", + "rustc-hash 1.1.0", "thiserror 2.0.20", ] @@ -2046,6 +2053,7 @@ dependencies = [ "tempfile", "thiserror 2.0.20", "tokio", + "windows-sys 0.61.2", "zeroize", ] @@ -2544,6 +2552,18 @@ dependencies = [ "hmac", ] +[[package]] +name = "pdf-writer" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5e456864a7a304047bff84977dc6fb162bd956475d40ba50b2dcecaada7f753" +dependencies = [ + "bitflags 2.13.1", + "itoa", + "memchr", + "ryu", +] + [[package]] name = "percent-encoding" version = "2.3.2" @@ -2951,6 +2971,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" +[[package]] +name = "rustc-hash" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b1e7f9a428571be2dc5bc0505c13fb6bf936822b894ec87abf8a08a4e51742d" + [[package]] name = "rustc_version" version = "0.4.1" @@ -3027,6 +3053,12 @@ version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f" +[[package]] +name = "ryu" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" + [[package]] name = "same-file" version = "1.0.6" @@ -3414,6 +3446,15 @@ dependencies = [ "float-cmp", ] +[[package]] +name = "subsetter" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38803281d1c23166c5ebcb455439a5d2afe711cc909cf88af72448c297756ad6" +dependencies = [ + "rustc-hash 2.1.3", +] + [[package]] name = "subtle" version = "2.6.1" @@ -4157,7 +4198,7 @@ dependencies = [ "portable-atomic", "profiling", "raw-window-handle", - "rustc-hash", + "rustc-hash 1.1.0", "smallvec", "thiserror 2.0.20", "wgpu-core-deps-apple", diff --git a/apps/ios/Snowbound.xcodeproj/project.pbxproj b/apps/ios/Snowbound.xcodeproj/project.pbxproj index 90582edbc6c67670d0933c2dd8613b9dc9bc7e88..494656c41f48fbe70e14f43441d296196416928c 100644 --- a/apps/ios/Snowbound.xcodeproj/project.pbxproj +++ b/apps/ios/Snowbound.xcodeproj/project.pbxproj @@ -8,14 +8,18 @@ /* Begin PBXBuildFile section */ 5B0000000000000000000101 /* Sample in Resources */ = {isa = PBXBuildFile; fileRef = 5B0000000000000000000201 /* Sample */; }; + 5B0000000000000000000126 /* Snowbound Guide in Resources */ = {isa = PBXBuildFile; fileRef = 5B0000000000000000000226 /* Snowbound Guide */; }; + 5B0000000000000000000102 /* Snowbound-Tahoe.icon in Resources */ = {isa = PBXBuildFile; fileRef = 5B0000000000000000000205 /* Snowbound-Tahoe.icon */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ 5B0000000000000000000200 /* Snowbound.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Snowbound.app; sourceTree = BUILT_PRODUCTS_DIR; }; 5B0000000000000000000201 /* Sample */ = {isa = PBXFileReference; lastKnownFileType = folder; name = Sample; path = "../../corpus/m6/native-features-01/notebook"; sourceTree = SOURCE_ROOT; }; + 5B0000000000000000000226 /* Snowbound Guide */ = {isa = PBXFileReference; lastKnownFileType = folder; name = "Snowbound Guide"; path = "../../docs/guide-notebook/Snowbound Guide"; sourceTree = SOURCE_ROOT; }; 5B0000000000000000000202 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 5B0000000000000000000203 /* Snowbound-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Snowbound-Bridging-Header.h"; sourceTree = ""; }; 5B0000000000000000000204 /* build-rust.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = "build-rust.sh"; sourceTree = ""; }; + 5B0000000000000000000205 /* Snowbound-Tahoe.icon */ = {isa = PBXFileReference; lastKnownFileType = folder.iconcomposer.icon; name = "Snowbound-Tahoe.icon"; path = "../../crates/snowbound/assets/icon/sources/Snowbound-Tahoe.icon"; sourceTree = SOURCE_ROOT; }; /* End PBXFileReference section */ /* Begin PBXFileSystemSynchronizedRootGroup section */ @@ -42,6 +46,8 @@ children = ( 5B0000000000000000000300 /* Snowbound */, 5B0000000000000000000201 /* Sample */, + 5B0000000000000000000226 /* Snowbound Guide */, + 5B0000000000000000000205 /* Snowbound-Tahoe.icon */, 5B0000000000000000000202 /* Info.plist */, 5B0000000000000000000203 /* Snowbound-Bridging-Header.h */, 5B0000000000000000000204 /* build-rust.sh */, @@ -121,6 +127,8 @@ buildActionMask = 2147483647; files = ( 5B0000000000000000000101 /* Sample in Resources */, + 5B0000000000000000000126 /* Snowbound Guide in Resources */, + 5B0000000000000000000102 /* Snowbound-Tahoe.icon in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -198,7 +206,7 @@ isa = XCBuildConfiguration; buildSettings = { ARCHS = arm64; - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_APPICON_NAME = "Snowbound-Tahoe"; CODE_SIGN_ENTITLEMENTS = Snowbound.entitlements; CURRENT_PROJECT_VERSION = 1; GENERATE_INFOPLIST_FILE = YES; @@ -235,7 +243,7 @@ isa = XCBuildConfiguration; buildSettings = { ARCHS = arm64; - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_APPICON_NAME = "Snowbound-Tahoe"; CODE_SIGN_ENTITLEMENTS = Snowbound.entitlements; CURRENT_PROJECT_VERSION = 1; GENERATE_INFOPLIST_FILE = YES; diff --git a/apps/ios/Snowbound/App.swift b/apps/ios/Snowbound/App.swift index 35753ed3d7871e21d337fb6f9211b7543d9bf944..37c8e5b2bf004626abf814304a791664146358b7 100644 --- a/apps/ios/Snowbound/App.swift +++ b/apps/ios/Snowbound/App.swift @@ -44,6 +44,32 @@ final class AppDelegate: UIResponder, UIApplicationDelegate { } } +/// The desktop's Appearance option: the system's, or light or dark regardless of it. +enum Appearance { + static let key = "appearance" + + static var style: UIUserInterfaceStyle { + get { UIUserInterfaceStyle(rawValue: UserDefaults.standard.integer(forKey: key)) ?? .unspecified } + set { + UserDefaults.standard.set(newValue.rawValue, forKey: key) + for case let scene as UIWindowScene in UIApplication.shared.connectedScenes { + for window in scene.windows { window.overrideUserInterfaceStyle = newValue } + } + } + } + + static func menu() -> UIMenu { + let choices: [(String, UIUserInterfaceStyle)] = [("System", .unspecified), ("Light", .light), ("Dark", .dark)] + return UIMenu( + title: "Appearance", image: UIImage(systemName: "circle.lefthalf.filled"), + children: choices.map { title, style in + let action = UIAction(title: title) { _ in Appearance.style = style } + action.state = Appearance.style == style ? .on : .off + return action + }) + } +} + /// Where the reader was, reopened on the next launch as Notes reopens its last note. private struct Place: Codable { let notebook: String @@ -71,6 +97,7 @@ final class SceneDelegate: UIResponder, UIWindowSceneDelegate, UISplitViewContro func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options: UIScene.ConnectionOptions) { guard let scene = scene as? UIWindowScene else { return } let window = UIWindow(windowScene: scene) + window.overrideUserInterfaceStyle = Appearance.style split.delegate = self split.scene = self split.preferredDisplayMode = .oneBesideSecondary diff --git a/apps/ios/Snowbound/CanvasView.swift b/apps/ios/Snowbound/CanvasView.swift index 584ee4abb5346049c6b9e4c8bc5d7cfd0ad91f11..a28de9f73aa5d87e6203d72203bd6713a6ec8a3e 100644 --- a/apps/ios/Snowbound/CanvasView.swift +++ b/apps/ios/Snowbound/CanvasView.swift @@ -771,7 +771,7 @@ final class CanvasView: UIScrollView, UIScrollViewDelegate, UITextInput, UITextI case #selector(copy(_:)), #selector(cut(_:)), #selector(delete(_:)), #selector(toggleBoldface(_:)), #selector(toggleItalics(_:)), #selector(toggleUnderline(_:)): return lo < hi - case #selector(paste(_:)): return UIPasteboard.general.hasStrings + case #selector(paste(_:)): return UIPasteboard.general.hasStrings || UIPasteboard.general.hasImages case #selector(select(_:)): return lo == hi && hasText case #selector(selectAll(_:)): return hasText && (lo > 0 || hi < endOfDocument.offset) default: return super.canPerformAction(action, withSender: sender) @@ -799,10 +799,15 @@ final class CanvasView: UIScrollView, UIScrollViewDelegate, UITextInput, UITextI edit(external: true) { replacing(range, with: "") } } - /// Pasted text takes the keyboard's language, as Windows gives the clipboard. + /// Pasted text takes the keyboard's language, as Windows gives the clipboard. Text wins + /// over a picture, which apps put beside copied text. override func paste(_ sender: Any?) { - guard let handle, let text = UIPasteboard.general.string else { return } - edit(external: true) { sb_paste(handle, text, textInputMode?.primaryLanguage ?? "") } + guard let handle else { return } + if let text = UIPasteboard.general.string { + edit(external: true) { sb_paste(handle, text, textInputMode?.primaryLanguage ?? "") } + } else if let image = UIPasteboard.general.image { + insertPicture(image) + } } override func select(_ sender: Any?) { @@ -958,7 +963,27 @@ final class CanvasView: UIScrollView, UIScrollViewDelegate, UITextInput, UITextI return focused } - /// Puts a JPEG or PNG after the caret's paragraph at `size` points. + /// A photo as OneNote 2010 can read it: JPEG, at most 2048 pixels across, shown at most + /// 220 points wide. + func insertPicture(_ image: UIImage) { + let longest: CGFloat = 2048 + let scale = min(1, longest / max(image.size.width * image.scale, image.size.height * image.scale)) + let pixels = CGSize( + width: (image.size.width * image.scale * scale).rounded(), + height: (image.size.height * image.scale * scale).rounded()) + let format = UIGraphicsImageRendererFormat() + format.scale = 1 + let drawn = UIGraphicsImageRenderer(size: pixels, format: format).image { _ in + image.draw(in: CGRect(origin: .zero, size: pixels)) + } + guard let data = drawn.jpegData(compressionQuality: 0.85) else { return } + // OneNote shows a picture's pixels at 96 per inch. + var size = CGSize(width: pixels.width * 0.75, height: pixels.height * 0.75) + if size.width > 220 { size = CGSize(width: 220, height: size.height * 220 / size.width) } + insertPicture(data, size: size) + } + + /// Puts a JPEG or PNG at the caret at `size` points. func insertPicture(_ data: Data, size: CGSize) { guard let handle else { return } edit(external: true) { diff --git a/apps/ios/Snowbound/Lists.swift b/apps/ios/Snowbound/Lists.swift index 6bb640f9ed14d97dd02f808d818bf92bc4ccfc61..0c31c065fbd92eeb58915cf5544f1bb615db1245 100644 --- a/apps/ios/Snowbound/Lists.swift +++ b/apps/ios/Snowbound/Lists.swift @@ -22,6 +22,8 @@ final class NotebooksViewController: UICollectionViewController, UIDocumentPicke /// Opening, or why the notebook cannot be. case status(notebook: String) case newNotebook, openFolder, connect + /// Copies the Snowbound Guide to On My iPhone and opens it, until it is there. + case guide /// New Notebook in iCloud Drive, and the way to it while iCloud Drive is off. case newInCloud, turnOnICloud } @@ -101,6 +103,7 @@ final class NotebooksViewController: UICollectionViewController, UIDocumentPicke guard let self else { return } Author.ask(from: self) {} }) + more.append(Appearance.menu()) provide(actions + [UIMenu(options: .displayInline, children: more)]) } ]) @@ -128,13 +131,15 @@ final class NotebooksViewController: UICollectionViewController, UIDocumentPicke func reload() { guard isViewLoaded else { return } + let copied = Notebooks.onDevice.contains { $0.source == .documents(path: Notebooks.guide) } + let guide: [Item] = Notebooks.guideOffered && !copied ? [.guide] : [] let cloud: [(Location, [Notebook], [Item])] = ICloud.documents != nil ? [(.icloud, Notebooks.inCloud, [.newInCloud])] : ICloud.signedIn ? [] : [(.icloud, [], [.turnOnICloud])] let locations: [(Location, [Notebook], [Item])] = cloud + (Notebooks.showsOnDevice ? [(.onDevice, Notebooks.onDevice, [.newNotebook])] : []) - + [(.elsewhere, Notebooks.elsewhere, [.openFolder, .connect])] + + [(.elsewhere, Notebooks.elsewhere, [.openFolder, .connect] + guide)] var sections = NSDiffableDataSourceSnapshot() sections.appendSections(locations.map(\.0)) dataSource.apply(sections, animatingDifferences: false) @@ -260,6 +265,10 @@ final class NotebooksViewController: UICollectionViewController, UIDocumentPicke content.text = "New Notebook…" content.image = UIImage(systemName: "plus") content.textProperties.color = .tintColor + case .guide: + content.text = "Open the Snowbound Guide" + content.image = UIImage(systemName: "book") + content.textProperties.color = .tintColor case .newNotebook, .openFolder, .connect: content.text = item == .newNotebook ? "New Notebook…" : item == .openFolder ? "Open Folder…" : "Connect to Server…" @@ -511,6 +520,7 @@ final class NotebooksViewController: UICollectionViewController, UIDocumentPicke if let settings = URL(string: UIApplication.openSettingsURLString) { UIApplication.shared.open(settings) } case .openFolder: openFolder() case .connect: connect() + case .guide: openGuide() case .location: break } return false @@ -586,6 +596,30 @@ final class NotebooksViewController: UICollectionViewController, UIDocumentPicke } } + /// Copies the guide the app carries to On My iPhone and opens the copy, so the carried one + /// stays as shipped. + private func openGuide() { + let copy = documentsDirectory.appendingPathComponent(Notebooks.guide) + background({ () -> String? in + guard !FileManager.default.fileExists(atPath: copy.path) else { return nil } + guard let carried = Bundle.main.url(forResource: Notebooks.guide, withExtension: nil) else { + return "The guide is missing from this copy of Snowbound." + } + do { try FileManager.default.copyItem(at: carried, to: copy) } catch { return error.localizedDescription } + return nil + }) { [weak self] problem in + guard let self else { return } + if let problem { return refuse("Can’t Open the Guide", problem) } + if !Notebooks.showsOnDevice { Notebooks.showsOnDevice = true } + rescan { [weak self] notebook in + guard notebook.source == .documents(path: Notebooks.guide), + let tab = notebook.tabs.first(where: \.readable) + else { return } + self?.onOpen?(tab, notebook) + } + } + } + private func refuse(_ title: String, _ message: String) { let alert = UIAlertController(title: title, message: message, preferredStyle: .alert) alert.addAction(UIAlertAction(title: "OK", style: .default)) diff --git a/apps/ios/Snowbound/Notebooks.swift b/apps/ios/Snowbound/Notebooks.swift index b90708d6335467d83cdf9042cfdf667272046b6f..b408549b0a0daad3010304af9144075cc7fddd5a 100644 --- a/apps/ios/Snowbound/Notebooks.swift +++ b/apps/ios/Snowbound/Notebooks.swift @@ -391,6 +391,10 @@ enum Notebooks { private static let key = "notebooks" private static let hidden = "hidesOnDevice" + /// The Snowbound Guide's folder, in the app and in Documents once copied there. + static let guide = "Snowbound Guide" + /// Whether the list offers the guide; off until Clover has read it through. + static let guideOffered = false private static let scripted = ProcessInfo.processInfo.environment["SNOWBOUND_NOTEBOOK"] /// The folders and sections in Documents, as On My iPhone lists them. private(set) static var onDevice: [Notebook] = [] diff --git a/apps/ios/Snowbound/PageViewController.swift b/apps/ios/Snowbound/PageViewController.swift index 0872c786d689e3c803c241a690cf332bef051f47..937623ef55f5be22250b987a417530218da2e5c2 100644 --- a/apps/ios/Snowbound/PageViewController.swift +++ b/apps/ios/Snowbound/PageViewController.swift @@ -330,7 +330,7 @@ final class PageViewController: UIViewController, PHPickerViewControllerDelegate guard let provider = results.first?.itemProvider, provider.canLoadObject(ofClass: UIImage.self) else { return } provider.loadObject(ofClass: UIImage.self) { [weak self] image, _ in guard let image = image as? UIImage else { return } - DispatchQueue.main.async { self?.insert(image) } + DispatchQueue.main.async { self?.canvas.insertPicture(image) } } } @@ -338,27 +338,7 @@ final class PageViewController: UIViewController, PHPickerViewControllerDelegate _ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any] ) { picker.dismiss(animated: true) - if let image = info[.originalImage] as? UIImage { insert(image) } - } - - /// A photo as OneNote 2010 can read it: JPEG, at most 2048 pixels across, shown at most - /// 220 points wide. - private func insert(_ image: UIImage) { - let longest: CGFloat = 2048 - let scale = min(1, longest / max(image.size.width * image.scale, image.size.height * image.scale)) - let pixels = CGSize( - width: (image.size.width * image.scale * scale).rounded(), - height: (image.size.height * image.scale * scale).rounded()) - let format = UIGraphicsImageRendererFormat() - format.scale = 1 - let drawn = UIGraphicsImageRenderer(size: pixels, format: format).image { _ in - image.draw(in: CGRect(origin: .zero, size: pixels)) - } - guard let data = drawn.jpegData(compressionQuality: 0.85) else { return } - // OneNote shows a picture's pixels at 96 per inch. - var size = CGSize(width: pixels.width * 0.75, height: pixels.height * 0.75) - if size.width > 220 { size = CGSize(width: 220, height: size.height * 220 / size.width) } - canvas.insertPicture(data, size: size) + if let image = info[.originalImage] as? UIImage { canvas.insertPicture(image) } } } diff --git a/arc/canvas.md b/arc/canvas.md index 6dffa9a1b2c4c033d282ded5370cbcf43c4d9eca..433dd51f6adeeb3ca4f8ca0f18a3459f6ad7313c 100644 --- a/arc/canvas.md +++ b/arc/canvas.md @@ -117,6 +117,14 @@ package. The page draws the PNG OneNote rendered of each pictures. Snowbound does not write XPS, so a printout page deleted and brought back by undo returns as that picture (`corpus/printout`). +Pictures go in as OneNote 2010 pastes and inserts them. At a caret in text the +paragraph splits around the picture, as around a file. On blank page the picture +lies on the page at the caret, and the caret moves to the grid row below it. A +picture takes the size its resolution gives it, or 96 dpi without one. Paste +takes files first (a picture file as its picture), then text, then a picture: +Finder offers a copied file's name and icon beside it, and other apps a picture +of copied text. + ## Recordings Record Audio and Record Video work as OneNote 2010's do. The caret's paragraph @@ -222,6 +230,19 @@ iOS) offers the dictionary's corrections, Ignore and Add to Dictionary, and the Spelling pane (F7) walks the page's marked words. A correction is an ordinary edit, one revision. Nothing about spelling is stored in the page. +## Printing and PDF + +`canvas::print` lays pages on paper as OneNote 2010 prints them (`corpus/print`): between +half-inch top and bottom margins with the margin origin an inch in, the whole page shrunk +when its content reaches past the paper's right edge, and each sheet after the first +starting at the line of text or picture the one before would have cut. Rule lines and +template art print across the paper; the page colour does not. The footer names the +section and numbers the sheets. `draw::pdf` writes the same primitives the screen paints +as PDF: text in subset fonts whose ToUnicode maps come from the laid-out text, so it +selects and searches, ligatures included; ink and shapes as paths; pictures and tag +icons as images. The desktop's Print hands that PDF to AppKit's print panel, the XDG print +portal or the shell's print verb for PDFs; Export as PDF saves it. + ## Search, dates, conflicts Smaller modules follow the same pattern of reproducing OneNote's behaviour diff --git a/corpus/equation-select/README.md b/corpus/equation-select/README.md new file mode 100644 index 0000000000000000000000000000000000000000..5a15a60f4aeff634e51a009b18ecec9824fcdea9 --- /dev/null +++ b/corpus/equation-select/README.md @@ -0,0 +1,26 @@ +# Edits reaching into equation objects + +`lab/` holds COM reads of a disposable OneNote 2010 clone editing a copy of +`corpus/math-edit/native-editor-4` by hand. `before.xml` is the page as it opened and +`after.xml` as it ended; the rest are reads between steps. + +- A mouse selection from inside `√x+1`'s root into `∛x`'s shows both objects selected + whole, and Backspace removes both paragraphs (`roots-deleted.xml`). +- From after `a₁` in `a₁+b₂` into the body of a sum ending its paragraph: the sum is taken + whole with the paragraph's end, so Backspace joins `a₁` to the integral below. +- From a fraction's numerator in `One a/b+c two` into the root of `Three √x+y four`: + both objects whole, leaving `One +y four`. +- Enter between `→` and `∞` in `lim_(n→∞) a_n` makes the limit an equation array + (`limit-enter.xml`). +- A click in "Type equation here." selects the placeholder whole; Enter leaves its + paragraph empty above a new one (`placeholder-enter.xml`), and typing `x` replaces it. +- A drag past a line's end also takes the paragraph's end: "Alpha beta", "Gamma delta" + selected from `Alp` to past `delta` delete to `Alpepsilon`. + +`candidate/` is the output of `selections_into_equation_objects_take_them_whole` in +`crates/canvas/tests/links_equations.rs`: the same edits through the editor on the same +page, one revision each. `cold/` is a fresh OneNote 2010 read of it, whose MathML matches +the lab's equation for equation. `tools/test_equation_select.py` checks this without a VM. +Regenerate with `CANVAS_EQUATION_SELECT_EXPORT` set to a new absolute directory while +running the test, then cold-open it with +`tools/native_runner.py OUTPUT COLD --expected-pages 1 --collect-notebook --screenshots`. diff --git a/corpus/equation-select/candidate/Open Notebook.onetoc2 b/corpus/equation-select/candidate/Open Notebook.onetoc2 new file mode 100644 index 0000000000000000000000000000000000000000..89012a8103c7db27f04b03e102d5417cdc4beedf GIT binary patch literal 1604 zcmZ3e|KIuM`!b(-j|5(YE0x6`JazkA*{R z+Y{?|_o zD2B+@KvfM~K!TCsn+$^rEax#W9QpG7>&B|EC4xZJARtn}(6HL$l+fgp+Fr{e+9U(j z%i3Y8rC%^K@Se&NJ8-Pdzw`dwC-bf>Du&5HbYqebc|{S11_qS`AOQsE#)HH`$}A)P zNXY+u?muIh$HYA!r!LkIU}(^*VCZ0A0qJ632moS;7eG9a4v=gBR8|5c3l;~-fN-P% z(92M^4A3laXuv|mdzW$3VbMd~F#ihy6@mZ{&@t!^1Q{maz%U^LY8BXYpcu$35CG{z zH%}NO2m~Axfcl{2Bgg~T%x1x1C&YAA^Fi?h@)XFuOh62>2SkJ1xNKYf6l6UBhtST( literal 0 HcmV?d00001 diff --git a/corpus/equation-select/candidate/links.one b/corpus/equation-select/candidate/links.one new file mode 100644 index 0000000000000000000000000000000000000000..499dffd89ef7f8485eb7399eb029b15a44a67623 GIT binary patch literal 46824 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 v0U8VDj1r?EFd72T5J1iJ?U^E0qKnMT;V4gUZ literal 0 HcmV?d00001 diff --git a/corpus/equation-select/cold/notebook/links.one b/corpus/equation-select/cold/notebook/links.one new file mode 100644 index 0000000000000000000000000000000000000000..f69a73aecc5830f99ad186d192a50833e42fd301 GIT binary patch literal 46824 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 + diff --git a/corpus/equation-select/cold/read/page-000.navigation.json b/corpus/equation-select/cold/read/page-000.navigation.json new file mode 100644 index 0000000000000000000000000000000000000000..83fb4df3362bb2ac7e9fa657fe6db76614b54e31 --- /dev/null +++ b/corpus/equation-select/cold/read/page-000.navigation.json @@ -0,0 +1,13 @@ +{ + "exit": 0, + "stdout": "", + "stderr": "", + "w": 800, + "h": 600, + "error": null, + "win": { + "title": "Read about Rust the Rust site - Microsoft OneNote", + "class": "Framework::CFrame", + "dialog": false + } +} \ No newline at end of file diff --git a/corpus/equation-select/cold/read/page-000.png b/corpus/equation-select/cold/read/page-000.png new file mode 100644 index 0000000000000000000000000000000000000000..185c6752d935f6f0f488fe86a26af5c7518c409a GIT binary patch literal 45260 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ƫ?Q)?11RyRpwO7TxXv7j)1!z^hKVPDjX_X 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 literal 0 HcmV?d00001 diff --git a/corpus/equation-select/cold/read/page-000.xml b/corpus/equation-select/cold/read/page-000.xml new file mode 100644 index 0000000000000000000000000000000000000000..5430f691678271143e6d97af31a84bee29a84c54 --- /dev/null +++ b/corpus/equation-select/cold/read/page-000.xml @@ -0,0 +1,5 @@ + +the Rust site]]>a1∫01x dx ]]>xn]]>ab]]>∏k=1nk ]]>a+b]]>x¯]]>x^]]>1234]]>x=1y=2]]>x2]]>x2]]>x]]>x]]>fxx2+1]]>∑nx ]]>ex+1]]>𝛼+𝛽]]>a+bc+d]]>x2+y2=z2]]>limn→∞⁡an]]>a+b]]>One four]]> diff --git a/corpus/equation-select/cold/read/payloads.json b/corpus/equation-select/cold/read/payloads.json new file mode 100644 index 0000000000000000000000000000000000000000..1ce91a413d6fff4d58765187b76756f0e97ae843 --- /dev/null +++ b/corpus/equation-select/cold/read/payloads.json @@ -0,0 +1,3 @@ +[ + +] \ No newline at end of file diff --git a/corpus/equation-select/cold/run.json b/corpus/equation-select/cold/run.json new file mode 100644 index 0000000000000000000000000000000000000000..f2bf1cb2aecf2b9d716003bc7c09f477b5cd7e3a --- /dev/null +++ b/corpus/equation-select/cold/run.json @@ -0,0 +1,18 @@ +{ + "notebook": "/private/tmp/eqlab/candidate", + "expected_pages": 1, + "author": null, + "author_timeout_seconds": 600, + "inspect": false, + "collect_notebook": true, + "base": { + "file": "win7-office-base.qcow2", + "format": "qcow2", + "sha256": "a1a4f8fab782ee14885ff801ca2f6347c208fdcfc3513637096f314315c89346", + "virtual_size": 68719476736 + }, + "scripts": { + "cold.ps1": "c177fc72ae6c2634d186f5671a880de20b09f9716532c37c69cb13aa15c7e331", + "read.ps1": "22bc760f955ef59bb5f0ccfd55271f8d868674084127fbe219e1048bd3777f35" + } +} diff --git a/corpus/equation-select/cold/scripts/cold.ps1 b/corpus/equation-select/cold/scripts/cold.ps1 new file mode 100644 index 0000000000000000000000000000000000000000..a0b99e7aeb86f4dc10032537800501a52ad65b4f --- /dev/null +++ b/corpus/equation-select/cold/scripts/cold.ps1 @@ -0,0 +1,27 @@ +param([Parameter(Mandatory=$true)][string]$Root, [string]$CloneHost = '') +Set-StrictMode -Version Latest +$ErrorActionPreference = 'Stop' +$root = [IO.Path]::GetFullPath($Root).TrimEnd('\') +if ([IO.Path]::GetDirectoryName($root) -ne 'C:\one-tests\runs') { + throw 'Choose a run directly below C:\one-tests\runs.' +} +if (Get-Process ONENOTE -ErrorAction SilentlyContinue) { throw 'Close OneNote before resetting its test cache.' } +$key = 'HKCU:\Software\Microsoft\Office\14.0\OneNote' +if ($CloneHost) { + if ($CloneHost -notmatch '^ONE-[A-Z0-9-]+$' -or [Environment]::MachineName -ne $CloneHost) { + throw 'The disposable clone hostname does not match this machine.' + } + New-Item "$key\Options\Paths" -Force | Out-Null + New-ItemProperty "$key\Options\Paths" -Name UnfiledNotesSection -PropertyType ExpandString -Value 'C:\one-tests\Loose.one' -Force | Out-Null +} elseif ((Get-ItemProperty "$key\Options\Paths").UnfiledNotesSection -ne 'C:\one-tests\Loose.one' -or + -not (Test-Path 'C:\one-tests\profile-original-cache')) { + throw 'Park the personal OneNote profile before resetting the test cache.' +} +$cache = Join-Path $env:LOCALAPPDATA 'Microsoft\OneNote\14.0' +$parked = Join-Path 'C:\one-tests\caches' ([IO.Path]::GetFileName($root)) +if (Test-Path $parked) { throw 'Choose a new run; its parked cache already exists.' } +New-Item -ItemType Directory -Path 'C:\one-tests\caches' -Force | Out-Null +if (Test-Path $cache) { Move-Item -LiteralPath $cache -Destination $parked } +if (Test-Path "$key\OpenNotebooks") { Remove-Item "$key\OpenNotebooks" -Recurse } +New-Item "$key\OpenNotebooks" | Out-Null +New-ItemProperty "$key\OpenNotebooks" -Name '1' -PropertyType String -Value "$root\notebook" | Out-Null diff --git a/corpus/equation-select/cold/scripts/read.ps1 b/corpus/equation-select/cold/scripts/read.ps1 new file mode 100644 index 0000000000000000000000000000000000000000..a42366b32e8baaf13dae92e9472cae7a071220cc --- /dev/null +++ b/corpus/equation-select/cold/scripts/read.ps1 @@ -0,0 +1,144 @@ +param( + [Parameter(Mandatory=$true)][string]$Root, + [int]$ExpectedPages = -1, + [switch]$UseCurrentCache, + [switch]$Pdf, + [switch]$KeepOpen, + [string]$CloneHost = '' +) +Set-StrictMode -Version Latest +$ErrorActionPreference = 'Stop' +$root = [IO.Path]::GetFullPath($Root).TrimEnd('\') +if ([IO.Path]::GetDirectoryName($root) -ne 'C:\one-tests\runs') { + throw 'Choose a run directly below C:\one-tests\runs.' +} +$notebook = Join-Path $root 'notebook' +$output = Join-Path $root 'read' +if (Test-Path $output) { throw 'Choose a new read destination.' } +if ($UseCurrentCache) { + if ((Get-ItemProperty 'HKCU:\Software\Microsoft\Office\14.0\OneNote\Options\Paths').UnfiledNotesSection -ne 'C:\one-tests\Loose.one') { + throw 'Park the personal OneNote profile before reading test notebooks.' + } +} else { + & "$PSScriptRoot\cold-current.ps1" -Root $root -CloneHost $CloneHost +} +New-Item -ItemType Directory -Path $output | Out-Null +$app = New-Object -ComObject OneNote.Application +$notebookId = '' +$failure = $null +try { + $app.OpenHierarchy($notebook, '', [ref]$notebookId, 0) + $process = Get-Process ONENOTE + @{ hostname = [Environment]::MachineName; onenote = $process.MainModule.FileVersionInfo.FileVersion; + powershell = $PSVersionTable.PSVersion.ToString(); schema = 'xs2010'; cold = (-not $UseCurrentCache.IsPresent) } | + ConvertTo-Json | Set-Content (Join-Path $output 'environment.json') -Encoding UTF8 + $sections = @() + foreach ($file in @(Get-ChildItem $notebook -Recurse | Where-Object { $_.Extension -eq '.one' })) { + $id = '' + $app.OpenHierarchy($file.FullName, '', [ref]$id, 0) + $sections += $id + } + $deadline = [DateTime]::UtcNow.AddSeconds(300) + $previous = '' + $lastChange = '' + $stableSince = [DateTime]::UtcNow + $settled = $false + do { + $pages = @{} + foreach ($section in $sections) { + $hierarchy = '' + $app.GetHierarchy($section, 4, [ref]$hierarchy, 1) + [xml]$xml = $hierarchy + foreach ($node in $xml.SelectNodes('//*[@path]')) { + if (-not $node.GetAttribute('path').StartsWith("$notebook\", [StringComparison]::OrdinalIgnoreCase)) { + throw 'OneNote opened a section outside the copied notebook.' + } + } + foreach ($node in $xml.SelectNodes('//*[local-name()="Page"]')) { + $id = $node.GetAttribute('ID') + $content = '' + $app.GetPageContent($id, [ref]$content, 1, 1) + $pages[$id] = $content + } + } + $signature = [String]::Join('|', @($pages.Keys | Sort-Object | ForEach-Object { $_ + $pages[$_] })) + if ($signature -ne $previous) { + $lastChange = $previous + $previous = $signature + $stableSince = [DateTime]::UtcNow + } + if ((($ExpectedPages -ge 0 -and $pages.Count -eq $ExpectedPages) -or + ($ExpectedPages -lt 0 -and $pages.Count -gt 0)) -and + ([DateTime]::UtcNow - $stableSince).TotalSeconds -ge 2) { $settled = $true; break } + Start-Sleep -Milliseconds 250 + } while ([DateTime]::UtcNow -lt $deadline) + if (-not $settled -or ($ExpectedPages -ge 0 -and $pages.Count -ne $ExpectedPages) -or ($ExpectedPages -lt 0 -and $pages.Count -eq 0)) { + [IO.File]::WriteAllText((Join-Path $output 'previous-signature.txt'), $lastChange, [Text.Encoding]::UTF8) + $index = 0 + foreach ($id in @($pages.Keys | Sort-Object)) { + [IO.File]::WriteAllText((Join-Path $output ('unsettled-{0:d3}.xml' -f $index)), $pages[$id], [Text.Encoding]::UTF8) + $index++ + } + $hierarchy = '' + $app.GetHierarchy($notebookId, 4, [ref]$hierarchy, 1) + [IO.File]::WriteAllText((Join-Path $output 'unsettled-hierarchy.xml'), $hierarchy, [Text.Encoding]::UTF8) + throw "Expected $ExpectedPages stable pages; OneNote returned $($pages.Count), settled=$settled." + } + $index = 0 + $payloads = @() + foreach ($id in @($pages.Keys | Sort-Object)) { + [IO.File]::WriteAllText((Join-Path $output ('page-{0:d3}.xml' -f $index)), $pages[$id], [Text.Encoding]::UTF8) + if ($Pdf) { + $pdfPath = Join-Path $output ('page-{0:d3}.pdf' -f $index) + $app.NavigateTo($id, '', $false) + $app.Publish($id, $pdfPath, 3, '') + if (-not (Test-Path $pdfPath) -or (Get-Item $pdfPath).Length -eq 0) { throw 'OneNote did not publish the page PDF.' } + } + [xml]$page = $pages[$id] + foreach ($file in $page.SelectNodes('//*[local-name()="InsertedFile" or local-name()="MediaFile"]')) { + $bytes = [IO.File]::ReadAllBytes($file.GetAttribute('pathCache')) + $hash = [BitConverter]::ToString([Security.Cryptography.SHA256]::Create().ComputeHash($bytes)).Replace('-', '').ToLowerInvariant() + [IO.File]::WriteAllBytes((Join-Path $output ($hash + '.attachment')), $bytes) + # A paragraph's file is named by its paragraph, one on the page by itself. + $owner = if ($file.ParentNode.LocalName -eq 'Page') { $file } else { $file.ParentNode } + $payloads += @{ page = $id; object = $owner.GetAttribute('objectID'); + kind = $file.LocalName; name = $file.GetAttribute('preferredName'); + sha256 = $hash; bytes = $bytes.Length } + } + $index++ + } + [IO.File]::WriteAllText((Join-Path $output 'payloads.json'), (ConvertTo-Json -InputObject $payloads -Depth 4), [Text.Encoding]::UTF8) + $all = '' + $app.GetHierarchy($notebookId, 4, [ref]$all, 1) + [xml]$finalTree = $all + $finalIds = @($finalTree.SelectNodes('//*[local-name()="Page"]') | ForEach-Object { $_.GetAttribute('ID') } | Sort-Object -Unique) + if ($finalIds.Count -ne $pages.Count -or @($finalIds | Where-Object { -not $pages.ContainsKey($_) }).Count -ne 0) { + throw 'The notebook hierarchy changed while collecting page evidence; repeat the cold read.' + } + [IO.File]::WriteAllText((Join-Path $output 'hierarchy.xml'), $all, [Text.Encoding]::UTF8) + Write-Output "Read $($sections.Count) sections and $($pages.Count) pages." +} catch { + $failure = $_ + [IO.File]::WriteAllText((Join-Path $output 'failure.txt'), ($_ | Out-String), [Text.Encoding]::UTF8) + throw +} finally { + try { + try { + if ($notebookId -and $CloneHost) { $app.SyncHierarchy($notebookId) } + if ($notebookId -and -not $KeepOpen -and (-not $UseCurrentCache -or $CloneHost)) { + $app.CloseNotebook($notebookId, $false) + } + } catch { + if ($null -eq $failure) { throw } + [IO.File]::WriteAllText((Join-Path $output 'cleanup-failure.txt'), ($_ | Out-String), [Text.Encoding]::UTF8) + } + } finally { + [void][Runtime.InteropServices.Marshal]::FinalReleaseComObject($app) + } + $app = $null + [GC]::Collect() + [GC]::WaitForPendingFinalizers() + if (-not $UseCurrentCache -and -not $CloneHost) { + Get-Process ONENOTE -ErrorAction SilentlyContinue | Wait-Process -Timeout 10 + } +} diff --git a/corpus/equation-select/cold/source.json b/corpus/equation-select/cold/source.json new file mode 100644 index 0000000000000000000000000000000000000000..53e25e1f3cf80609f44a3d4904ef11986ad4e1da --- /dev/null +++ b/corpus/equation-select/cold/source.json @@ -0,0 +1,14 @@ +[ + { + "path": "Open Notebook.onetoc2", + "bytes": 1604, + "sha256": "90206bfbbba99bcebfd2d4896c458dbca5d83120f6649b11abb885730fdb69b9", + "mtime_ns": 1790805000764803414 + }, + { + "path": "links.one", + "bytes": 46824, + "sha256": "2e6bfeb5f7eded840d97512230cf18bb67924d4e6d28484cf957e9882eaedae1", + "mtime_ns": 1790805000764567872 + } +] diff --git a/corpus/equation-select/cold/teardown.json b/corpus/equation-select/cold/teardown.json new file mode 100644 index 0000000000000000000000000000000000000000..05a47793de40f322e745c4c4183727e3590ecf70 --- /dev/null +++ b/corpus/equation-select/cold/teardown.json @@ -0,0 +1 @@ +{"absent": true} diff --git a/corpus/equation-select/lab/after.xml b/corpus/equation-select/lab/after.xml new file mode 100644 index 0000000000000000000000000000000000000000..70a4b86d7cbd59d3bde5b5895e76ee605eb6f78e --- /dev/null +++ b/corpus/equation-select/lab/after.xml @@ -0,0 +1,5 @@ + +the Rust site]]>a1∫01x dx ]]>xn]]>ab]]>∏k=1nk ]]>a+b]]>x¯]]>x^]]>1234]]>x=1y=2]]>x2]]>x2]]>x]]>x]]>fxx2+1]]>∑nx ]]>ex+1]]>𝛼+𝛽]]>a+bc+d]]>x2+y2=z2]]>limn→∞⁡an]]>a+b]]>One four]]>x]]> diff --git a/corpus/equation-select/lab/before.xml b/corpus/equation-select/lab/before.xml new file mode 100644 index 0000000000000000000000000000000000000000..44ab03a193fc06752be15f08eaf679ac7436e75d --- /dev/null +++ b/corpus/equation-select/lab/before.xml @@ -0,0 +1,3 @@ + +the Rust site]]>a1+b2]]>Type equation here.]]>∑i=1ni ]]>∫01x dx ]]>x+1 ]]>x3]]>xn]]>ab]]>∏k=1nk ]]>a+b]]>x¯]]>x^]]>1234]]>x=1y=2]]>x2]]>x2]]>x]]>x]]>fxx2+1]]>∑nx ]]>ex+1]]>𝛼+𝛽]]>a+bc+d]]>x2+y2=z2]]>limn→∞⁡an]]>a+b]]> diff --git a/corpus/equation-select/lab/limit-enter.xml b/corpus/equation-select/lab/limit-enter.xml new file mode 100644 index 0000000000000000000000000000000000000000..725b6a2d1931aa1a38f2f465a23db83206afed09 --- /dev/null +++ b/corpus/equation-select/lab/limit-enter.xml @@ -0,0 +1,5 @@ + +the Rust site]]>a1∫01x dx ]]>xn]]>ab]]>∏k=1nk ]]>a+b]]>x¯]]>x^]]>1234]]>x=1y=2]]>x2]]>x2]]>x]]>x]]>fxx2+1]]>∑nx ]]>ex+1]]>𝛼+𝛽]]>a+bc+d]]>x2+y2=z2]]>limn→∞⁡an]]>a+b]]>One four]]> diff --git a/corpus/equation-select/lab/placeholder-enter.xml b/corpus/equation-select/lab/placeholder-enter.xml new file mode 100644 index 0000000000000000000000000000000000000000..825e5df9e0acd27edc87c995c64b2fea8f402c48 --- /dev/null +++ b/corpus/equation-select/lab/placeholder-enter.xml @@ -0,0 +1,5 @@ + +the Rust site]]>a1∫01x dx ]]>xn]]>ab]]>∏k=1nk ]]>a+b]]>x¯]]>x^]]>1234]]>x=1y=2]]>x2]]>x2]]>x]]>x]]>fxx2+1]]>∑nx ]]>ex+1]]>𝛼+𝛽]]>a+bc+d]]>x2+y2=z2]]>limn→∞⁡an]]>a+b]]>One four]]> diff --git a/corpus/equation-select/lab/roots-deleted.xml b/corpus/equation-select/lab/roots-deleted.xml new file mode 100644 index 0000000000000000000000000000000000000000..a97fb26f4821217994b4734d3cee2767c856881b --- /dev/null +++ b/corpus/equation-select/lab/roots-deleted.xml @@ -0,0 +1,3 @@ + +the Rust site]]>a1+b2]]>Type equation here.]]>∑i=1ni ]]>∫01x dx ]]>xn]]>ab]]>∏k=1nk ]]>a+b]]>x¯]]>x^]]>1234]]>x=1y=2]]>x2]]>x2]]>x]]>x]]>fxx2+1]]>∑nx ]]>ex+1]]>𝛼+𝛽]]>a+bc+d]]>x2+y2=z2]]>limn→∞⁡an]]>a+b]]> diff --git a/corpus/print/README.md b/corpus/print/README.md new file mode 100644 index 0000000000000000000000000000000000000000..719d2d58d9b650d671f30a7b689a36f0ddbfc764 --- /dev/null +++ b/corpus/print/README.md @@ -0,0 +1,33 @@ +# Print + +`native/Print.one` is a section the COM API made in OneNote 2010: "Printing test", a +ruled page (horizontal lines every 0.2 points, as OneNote reads the XML's spacing, and a +margin line) with a 70-paragraph outline running past the first sheet, a picture, an +outline near the first sheet's foot and one reaching 867 points across; "Second page"; +and "Wide 1200" and "Wide 560", titled pages whose one word sits that far across. +`native/section.pdf` is OneNote's File, Save As, PDF of the section, the same sheets File, +Print prints. `native/rules-section.pdf` is its PDF of `page-background/candidate`. + +What they show, on a 612.36 by 790.92 point Letter sheet: + +- The page prints between 36-point top and bottom margins, the margin origin at (72, 36). + Content reaching past the paper's right edge shrinks the whole page to fit it with 9 + points to spare: "Printing test" prints at 0.672, "Wide 560" at 0.978, "Wide 1200" at + 0.484. +- A sheet ends before the first line it would cut: the first holds paragraphs 1 to 37 and + the second starts at paragraph 38. Content below that on the first sheet waits for the + next. +- Rule lines print across the paper's whole width, down to the bottom margin of every + sheet. The page colour does not print. Template art does, and a page longer than a sheet + only through its art ("VeryLargeGrid") takes a second sheet. +- The footer, "Print Page 1", is the section's name and the sheet's number counted across + the whole printout, in 10-point Times New Roman centred near the paper's bottom edge; it + shrinks with the page towards the bottom left. No header prints; the title, date and + time are the page's own. + +Print Preview and Settings offers Print range (Current Page, Page Group, Current Section), +Paper size, Scale content to paper width (on), Orientation, Footer (section and page +number, page number, section, none) and Start page numbering at 1. Save As, PDF offers +Selected Pages, Current Section and Current Notebook. + +`crates/canvas/src/print.rs` checks Snowbound's sheets against these without a VM. diff --git a/corpus/print/native/Print.one b/corpus/print/native/Print.one new file mode 100644 index 0000000000000000000000000000000000000000..2288f4f00964171131c73248afb794d00923b9c9 GIT binary patch literal 47496 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 ^v@{JdXf7tDLx&_}d!433eVsy~(Y6 zR2tZBO4rOc_V?&@8a2oB>PJ5dvkoF|`&k%%p4uGB*Heifx%MT@_nvINGmp1bXsB}h zd?)O2kIveQ_9Gnl7;>S*{F0FW7-pw*5}d4rXo-PIN7T%E}IA*&d$UPA6>}$oI+W z2fOG)^2@P@*0bIrUq`;x7=u;)uyLz%T55J$UTR7~puR)efc&)ny~s&pXi%U&B*^^D za;g33$?c-@^~T=RXSe4fPm*5f&nEh}40|s0^kjBu;aBAO?fm18BUh3a1=>AU&mLWepZno+yW(0`XsI!_gtkzk~Dt3;xF%JQQ<=bSB z&16u<}oCZOK1^K8=@;ga5%2g-sjvvS|gctFy41qh5NQ zm1UjNS=io@XPMUe|DH+2zrAsn%WqQya{V8DzJ%zX()Zz(wr>ho^P!A+z+Yci=IcnH zoj($ODZQSh?K69ldj9qKiZGsH&WHfKDYs$N(ylRhS?=#eaV%TU?%wlv8?5qe_~6gemkVcsAM;^ryOdxz$w_V$Ft^IOw#(1tdA)SH uGIomb8&+y4Xq6O3vA literal 0 HcmV?d00001 diff --git a/corpus/print/native/rules-section.pdf b/corpus/print/native/rules-section.pdf new file mode 100644 index 0000000000000000000000000000000000000000..410af674027acfb2e1ef522f91dd55f6b06a5a5d GIT binary patch literal 145613 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 literal 0 HcmV?d00001 diff --git a/corpus/print/native/section.pdf b/corpus/print/native/section.pdf new file mode 100644 index 0000000000000000000000000000000000000000..3b461b4717ee33c4c17d27791f17915abcb3ab96 GIT binary patch literal 168568 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�X^(olq|VtM;yj#7BRJ)?0JV+1F|oc-X$` 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 literal 0 HcmV?d00001 diff --git a/crates/canvas/Cargo.toml b/crates/canvas/Cargo.toml index d83605e92f3122f8d2820759c5d89655f6a83ae7..d96a8c6f405146d8a63bf188521aeca85e63664b 100644 --- a/crates/canvas/Cargo.toml +++ b/crates/canvas/Cargo.toml @@ -8,6 +8,8 @@ publish = false gpu = ["draw/render", "dep:color_quant", "dep:image", "dep:png", "dep:resvg", "dep:sha2"] # How a page responds to input and presents itself to assistive technology. interaction = ["gpu", "dep:accesskit"] +# Pages printed as PDF, as OneNote prints them. +pdf = ["interaction", "draw/pdf"] [dependencies] draw = { path = "../draw", default-features = false } @@ -35,6 +37,7 @@ path = "src/bin/page_probe.rs" [dev-dependencies] draw = { path = "../draw", features = ["wgpu"] } +miniz_oxide = "0.8" accesskit_consumer = "0.39.0" pollster = "0.4" wgpu.workspace = true @@ -42,3 +45,7 @@ wgpu.workspace = true [[example]] name = "render_page" required-features = ["gpu"] + +[[example]] +name = "print_pdf" +required-features = ["pdf"] diff --git a/crates/canvas/examples/print_pdf.rs b/crates/canvas/examples/print_pdf.rs new file mode 100644 index 0000000000000000000000000000000000000000..a2615124b8b16e09fdfc558c48d7ed16c3208190 --- /dev/null +++ b/crates/canvas/examples/print_pdf.rs @@ -0,0 +1,40 @@ +//! Writes a section's pages, or one titled page, as the PDF Print and Export as PDF make. +//! `print_pdf SECTION.one NEW.pdf [TITLE] [--a4]` + +use canvas::{layout::TextEngine, print}; +use onestore::{RevisionIndex, Store, document::Document, page::Page}; +use std::{env, fs, path::Path}; + +fn main() -> Result<(), Box> { + let args: Vec = env::args().skip(1).collect(); + let [section, destination, rest @ ..] = args.as_slice() else { + return Err("Expected a section, a new PDF path and optionally a page title".into()); + }; + let a4 = rest.iter().any(|arg| arg == "--a4"); + let title = rest.iter().find(|arg| *arg != "--a4"); + let bytes = fs::read(section)?; + let store = Store::parse(&bytes)?; + let index = RevisionIndex::parse(&store)?; + let document = Document::parse(&index)?; + let mut spaces: Vec<_> = document + .pages()? + .into_iter() + .map(|(space, _)| space) + .collect(); + spaces.dedup(); + let pages = spaces + .into_iter() + .map(|space| Page::from_space(&document, space)) + .collect::, _>>()? + .into_iter() + .filter(|page| title.is_none_or(|title| page.title == *title)) + .collect(); + let name = Path::new(section) + .file_stem() + .and_then(|stem| stem.to_str()) + .unwrap_or_default(); + let paper = if a4 { print::A4 } else { print::LETTER }; + let pdf = print::pdf(pages, &mut TextEngine::default(), paper, name)?; + fs::write(destination, pdf)?; + Ok(()) +} diff --git a/crates/canvas/examples/scratch_eqref.rs b/crates/canvas/examples/scratch_eqref.rs new file mode 100644 index 0000000000000000000000000000000000000000..9f5aab70bf7be18cbc32f13a60e08fa50a84b333 --- /dev/null +++ b/crates/canvas/examples/scratch_eqref.rs @@ -0,0 +1,667 @@ +//! Every place the canvas shows a page's content as a placeholder, draws it read-only, or +//! refuses an ordinary edit as content it cannot edit, across the active pages of every +//! section under the given directories, grouped by kind as Markdown. Identical sections +//! count once. +//! +//! `cargo run --release -p canvas --features gpu --example unsupported_inventory -- corpus` + +use canvas::{ + document::TextPosition, + editor::{CanvasEditor, EditorError, TextOutline}, + layout::{LayoutError, TextEngine}, + outline::Arrange, +}; +use onestore::{ + Arena, ExGuid, Section, + page::{ + Image, Outline, Page, PageObject, PageParagraph, Paragraph, ParagraphContent, + text::{Affinity, EditError}, + }, +}; +use std::{ + collections::{BTreeMap, BTreeSet, hash_map::DefaultHasher}, + hash::{Hash, Hasher}, + path::{Path, PathBuf}, +}; + +#[derive(Default)] +struct Inventory { + /// Kind to the places it occurs, as `section — page`. + kinds: BTreeMap<(Stage, String), Vec>, + sections: usize, + pages: usize, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] +enum Stage { + /// Drawn as an "Unsupported content" (or "Image unavailable") box. + Placeholder, + /// Drawn as stored, but the editor cannot hold it. + ReadOnly, + /// An ordinary edit the editor refuses as content it cannot edit. + Refused, + /// The page or section does not open at all. + Failure, +} + +impl Inventory { + fn add(&mut self, stage: Stage, kind: impl Into, place: &str) { + self.kinds + .entry((stage, kind.into())) + .or_default() + .push(place.to_owned()); + } +} + +/// MS-ONE's names for the object kinds it documents, and the observed undocumented ones. +fn jcid_name(jcid: u32) -> String { + let name = match jcid { + 0x60007 => "section", + 0x60008 => "page series", + 0x6000b => "page", + 0x6000c => "outline", + 0x6000d => "outline element", + 0x6000e => "rich text", + 0x60011 => "picture", + 0x60012 => "number list", + 0x60014 => "ink container", + 0x60019 => "outline group", + 0x60022 => "table", + 0x60023 => "table row", + 0x60024 => "table cell", + 0x6002c => "title", + 0x60035 => "embedded file", + 0x60037 => "page manifest", + 0x6003c => "version history", + 0x6003d => "version proxy", + _ => "undocumented", + }; + format!("jcid 0x{jcid:05x} ({name})") +} + +fn unsupported_error(error: &EditorError) -> bool { + matches!( + error, + EditorError::Layout(LayoutError::UnsupportedContent) + | EditorError::Edit(EditError::UnsupportedContent) + ) +} + +/// What a text paragraph holds that bears on editing it. +fn traits(text: &Paragraph) -> Vec<&'static str> { + let spans = text.spans(); + let mut traits = Vec::new(); + if text.text().contains('\u{fffc}') + || spans.iter().any(|s| s.format.embedded_object == Some(true)) + { + traits.push("embedded object in text"); + } + if spans.iter().any(|s| s.format.math == Some(true)) { + traits.push("equation"); + } + if spans.iter().any(|s| s.format.hyperlink == Some(true)) { + traits.push("link"); + } + if spans.iter().any(|s| s.format.hidden == Some(true)) { + traits.push("hidden text"); + } + if text.text().is_empty() { + traits.push("empty"); + } + traits +} + +/// Why `node`, alone in an outline, does not lay out as content the canvas understands. +fn culprit( + engine: &mut TextEngine, + outline: &Outline, + node: &PageParagraph, + page: &Page, +) -> Option { + let alone = Outline { + paragraphs: vec![PageParagraph { + parent: None, + level: 1, + ..node.clone() + }], + unsupported: Vec::new(), + ..outline.clone() + }; + match alone.layout(engine, &page.definitions) { + Err(LayoutError::UnsupportedContent) => {} + _ => return None, + } + Some(match &node.content { + ParagraphContent::Unsupported(u) => format!("holds {}", jcid_name(u.jcid)), + ParagraphContent::Table(table) if !table.tags.is_empty() => "table with note tags".into(), + ParagraphContent::Table(table) => { + let cells = || table.rows.iter().flat_map(|row| &row.cells); + if let Some(cell) = cells().find(|cell| !cell.unsupported.is_empty()) { + format!( + "table cell holding {}", + cell.unsupported + .iter() + .map(|u| jcid_name(u.jcid)) + .collect::>() + .join(", ") + ) + } else { + let inner = cells() + .flat_map(|cell| &cell.paragraphs) + .find_map(|inner| culprit(engine, outline, inner, page)); + format!( + "table cell: {}", + inner.unwrap_or_else(|| "nested content".into()) + ) + } + } + ParagraphContent::Image(_) => "picture without a size".into(), + ParagraphContent::Ink(_) => "handwriting without strokes".into(), + ParagraphContent::Attachment(_) => "file".into(), + ParagraphContent::Text(text) => { + let lists: Vec = node + .lists + .iter() + .filter_map(|id| page.definitions.get(id)) + .map(|definition| format!("{:?}", definition.kind)) + .collect(); + if !lists.is_empty() { + format!("list marker {}", lists.join(", ")) + } else if text + .text + .spans() + .iter() + .any(|s| s.format.math == Some(true)) + { + "equation the math layout does not parse".into() + } else { + format!("text ({})", traits(&text.text).join(", ")) + } + } + }) +} + +/// Why an outline the page shows is not editable. +fn diagnose(engine: &mut TextEngine, outline: &Outline, page: &Page) -> Vec { + let mut reasons: Vec = outline + .unsupported + .iter() + .map(|u| format!("outline child {}", jcid_name(u.jcid))) + .collect(); + reasons.extend( + outline + .paragraphs + .iter() + .filter_map(|node| culprit(engine, outline, node, page)), + ); + if reasons.is_empty() { + let text = outline.paragraphs.iter().any(|node| { + node.text().is_some() + || matches!(&node.content, ParagraphContent::Table(t) + if t.rows.iter().flat_map(|r| &r.cells).any(|c| !c.paragraphs.is_empty())) + }); + reasons.push(if text { + match TextOutline::from_outline(engine, outline, &page.definitions) { + Err(error) => format!("editor: {error}"), + Ok(_) => "outline on its own is editable".into(), + } + } else { + let kinds: BTreeSet<&str> = outline + .paragraphs + .iter() + .map(|node| match node.content { + ParagraphContent::Image(_) => "pictures", + ParagraphContent::Attachment(_) => "files", + ParagraphContent::Ink(_) => "handwriting", + _ => "other", + }) + .collect(); + format!( + "no paragraph of text (only {})", + kinds.into_iter().collect::>().join(", ") + ) + }); + } + reasons +} + +/// A picture that draws as "Image unavailable": no data, or (with `--features gpu`) data +/// the renderer does not decode, named by its leading bytes. +fn picture(image: &Image, at: &str, inventory: &mut Inventory, place: &str) { + let Some(bytes) = &image.bytes else { + return inventory.add( + Stage::Placeholder, + format!("{at} picture without data"), + place, + ); + }; + #[cfg(feature = "gpu")] + if [Some(bytes), image.display.as_ref()] + .into_iter() + .flatten() + .all(|bytes| draw::RasterImage::measure(bytes).is_err()) + { + let format = match &bytes[..bytes.len().min(4)] { + [0x50, 0x4b, 3, 4] => "a zip package (XPS printout)", + [1, 0, 0, 0] => "EMF", + [0xd7, 0xcd, 0xc6, 0x9a] | [1, 0, 9, 0] => "WMF", + [b'B', b'M', ..] => "BMP", + _ => "an unknown format", + }; + inventory.add( + Stage::Placeholder, + format!("{at} picture stored as {format}"), + place, + ); + } + #[cfg(not(feature = "gpu"))] + let _ = bytes; +} + +/// Pictures that draw as "Image unavailable" and objects the model keeps aside. +fn scan_paragraphs(nodes: &[PageParagraph], at: &str, inventory: &mut Inventory, place: &str) { + for node in nodes { + match &node.content { + ParagraphContent::Unsupported(u) => inventory.add( + Stage::Placeholder, + format!("{at} paragraph holding {}", jcid_name(u.jcid)), + place, + ), + ParagraphContent::Image(image) => picture(image, at, inventory, place), + ParagraphContent::Table(table) => { + for cell in table.rows.iter().flat_map(|row| &row.cells) { + for u in &cell.unsupported { + inventory.add( + Stage::Placeholder, + format!("table cell child {}", jcid_name(u.jcid)), + place, + ); + } + scan_paragraphs(&cell.paragraphs, "table cell", inventory, place); + } + } + _ => {} + } + } +} + +/// Ordinary edits at every text paragraph of every editable outline: typing at its start, +/// middle and end, Enter, Backspace at its start, Delete at its end, and deleting from its +/// middle into the next. +fn probe( + editor: &mut CanvasEditor, + engine: &mut TextEngine, + inventory: &mut Inventory, + place: &str, +) { + let ids: Vec = editor.outlines().iter().map(|o| o.id).collect(); + for id in ids { + if editor.focus_outline(id).is_err() { + continue; + } + let document = editor.active_outline().document(); + let containers = containers(document.nodes()); + let leaves: Vec<(Option, Paragraph)> = document + .text_nodes() + .map(|node| { + ( + containers.get(&node.id).copied().flatten(), + node.text().unwrap().text.clone(), + ) + }) + .collect(); + for (index, (container, text)) in leaves.iter().enumerate() { + let length = text.text().encode_utf16().count() as u32; + // The middle of what shows, where a click could put the caret. + let Ok(projection) = text.project() else { + continue; + }; + let shown = projection.text(); + let middle = shown + .text() + .char_indices() + .map(|(at, _)| at) + .nth(shown.text().chars().count() / 2) + .and_then(|at| shown.utf16_offset(at).ok()) + .and_then(|at| projection.source_offset(at, Affinity::Downstream).ok()) + .unwrap_or(length); + let at = |offset| TextPosition { + paragraph: index, + offset, + }; + let next = leaves.get(index + 1); + let mut probes: Vec<(&str, [TextPosition; 2], Probe)> = vec![ + ("typing at a paragraph's start", [at(0); 2], Probe::Type), + ("typing inside a paragraph", [at(middle); 2], Probe::Type), + ("typing at a paragraph's end", [at(length); 2], Probe::Type), + ("Enter inside a paragraph", [at(middle); 2], Probe::Enter), + ( + "Delete at a paragraph's end", + [at(length); 2], + Probe::Delete, + ), + ]; + if index > 0 { + probes.push(( + "Backspace at a paragraph's start", + [at(0); 2], + Probe::Backspace, + )); + } + if let Some((_, next_text)) = next { + let end = next_text.text().encode_utf16().count() as u32 / 2; + probes.push(( + "deleting a selection into the next paragraph", + [ + at(middle), + TextPosition { + paragraph: index + 1, + offset: end, + }, + ], + Probe::Backspace, + )); + } + for (name, positions, kind) in probes { + if editor.select(positions.into()).is_err() { + continue; + } + let result = match kind { + Probe::Type => editor.insert(engine, "x").map(|()| true), + Probe::Enter => editor.enter(engine, false).map(|()| true), + Probe::Delete => editor.delete(engine, false), + Probe::Backspace => editor.delete(engine, true), + }; + match result { + Ok(true) => { + editor.undo(engine).ok(); + } + Ok(false) => {} + Err(error) if unsupported_error(&error) => { + let show = |t: &Paragraph, o: u32| { + let b = t.byte_offset(o).unwrap_or(0); + let v = |s: &str| s.replace('\u{fdd0}', "⟨").replace('\u{fdef}', "⟩").replace('\u{fdee}', "|").replace('\u{fffc}', "¤"); + format!("{}‸{}", v(&t.text()[..b]), v(&t.text()[b..])) + }; + let a = show(text, positions[0].offset); + let b = if positions[1].paragraph != index { show(&leaves[positions[1].paragraph].1, positions[1].offset) } else { String::new() }; + eprintln!("REFUSED {name} @ {place}\n A: {a}\n B: {b}"); + let crossing = positions[0].paragraph != positions[1].paragraph + || name.starts_with("Backspace") + || name.starts_with("Delete"); + let neighbour = match name { + n if n.starts_with("Backspace") => leaves.get(index - 1), + _ if crossing => next, + _ => None, + }; + let mut why: Vec<&str> = traits(text); + if let Some((other, other_text)) = neighbour { + if other != container { + why.push("across a table cell boundary"); + } + why.extend(traits(other_text).into_iter().map(|t| match t { + "embedded object in text" => "next to an embedded object", + "equation" => "next to an equation", + "link" => "next to a link", + t => t, + })); + } + if container.is_some() { + why.push("in a table cell"); + } + why.sort(); + why.dedup(); + inventory.add( + Stage::Refused, + format!("{name} [{}]", why.join(", ")), + place, + ); + } + Err(_) => {} + } + } + } + } +} + +#[derive(Clone, Copy)] +enum Probe { + Type, + Enter, + Delete, + Backspace, +} + +/// Each paragraph's table cell, `None` at the outline's top. +fn containers(nodes: &[PageParagraph]) -> BTreeMap> { + let mut map = BTreeMap::new(); + let mut pending = vec![(None, nodes)]; + while let Some((container, nodes)) = pending.pop() { + for node in nodes { + map.insert(node.id, container); + if let ParagraphContent::Table(table) = &node.content { + for cell in table.rows.iter().flat_map(|row| &row.cells) { + pending.push((Some(cell.id), cell.paragraphs.as_slice())); + } + } + } + } + map +} + +fn page(engine: &mut TextEngine, page: Page, place: &str, inventory: &mut Inventory) { + for object in &page.objects { + match object { + PageObject::Unsupported(u) => inventory.add( + Stage::Placeholder, + format!("page object {}", jcid_name(u.jcid)), + place, + ), + PageObject::Image(image) => picture(image, "page", inventory, place), + PageObject::Outline(outline) => { + for u in &outline.unsupported { + inventory.add( + Stage::Placeholder, + format!("outline child {}", jcid_name(u.jcid)), + place, + ); + } + scan_paragraphs(&outline.paragraphs, "outline", inventory, place); + } + PageObject::Title(title) => { + for outline in &title.outlines { + scan_paragraphs(&outline.paragraphs, "title", inventory, place); + } + } + _ => {} + } + } + let mut editor = match CanvasEditor::from_page(page.clone(), engine) { + Ok(editor) => editor, + Err(error) => { + inventory.add( + Stage::Failure, + format!("page does not open: {error}"), + place, + ); + return; + } + }; + for object in &page.objects { + let (outlines, title) = match object { + PageObject::Outline(outline) => (std::slice::from_ref(outline), None), + PageObject::Title(title) => (title.outlines.as_slice(), Some(title)), + _ => continue, + }; + for outline in outlines { + if editor.has_page_outline(outline.id) + || editor.outlines().iter().any(|o| o.id == outline.id) + { + continue; + } + if let Some(title) = title { + if title.date == Some(outline.id) { + if editor.date().is_none() { + inventory.add(Stage::ReadOnly, "page date the date editor declines", place); + } + continue; + } + if !outline.title { + continue; + } + } + let placeholder = matches!( + outline.layout(engine, &page.definitions), + Err(LayoutError::UnsupportedContent) + ); + let at = if title.is_some() { "title" } else { "outline" }; + for reason in diagnose(engine, outline, &page) { + let stage = if placeholder { + Stage::Placeholder + } else { + Stage::ReadOnly + }; + let whole = if placeholder { + format!("whole {at} as a box: {reason}") + } else { + format!("{at} read-only: {reason}") + }; + inventory.add(stage, whole, place); + } + } + } + probe(&mut editor, engine, inventory, place); +} + +fn section(engine: &mut TextEngine, path: &Path, root: &Path, inventory: &mut Inventory) { + let Ok(image) = std::fs::read(path) else { + return; + }; + let name = path + .strip_prefix(root) + .unwrap_or(path) + .display() + .to_string(); + let arena = Arena::default(); + let mut section = match Section::open(&arena, image) { + Ok(section) => section, + Err(error) => { + inventory.add( + Stage::Failure, + format!("section does not open: {}", error.message), + &name, + ); + return; + } + }; + inventory.sections += 1; + let pages = match section.pages() { + Ok(pages) => pages, + Err(error) => { + inventory.add( + Stage::Failure, + format!("page list does not read: {}", error.message), + &name, + ); + return; + } + }; + for (space, title, _) in pages { + inventory.pages += 1; + let place = format!("{name} — {title}"); + match section.page(space) { + Ok(model) => page(engine, model, &place, inventory), + Err(error) => inventory.add( + Stage::Failure, + format!("page does not read: {}", error.message), + &place, + ), + } + } +} + +fn sections(directory: &Path, out: &mut Vec) { + let Ok(entries) = std::fs::read_dir(directory) else { + return; + }; + let mut entries: Vec = entries.flatten().map(|entry| entry.path()).collect(); + entries.sort(); + for path in entries { + if path.is_dir() { + sections(&path, out); + } else if path.extension().is_some_and(|e| e == "one") { + out.push(path); + } + } +} + +fn main() { + let roots: Vec = std::env::args().skip(1).map(PathBuf::from).collect(); + let mut engine = TextEngine::default(); + let mut inventory = Inventory::default(); + let mut seen = BTreeSet::new(); + let mut duplicates = 0; + for root in &roots { + let mut paths = Vec::new(); + sections(root, &mut paths); + for path in paths { + let Ok(bytes) = std::fs::read(&path) else { + continue; + }; + let mut hasher = DefaultHasher::new(); + bytes.hash(&mut hasher); + if !seen.insert(hasher.finish()) { + duplicates += 1; + continue; + } + section(&mut engine, &path, root, &mut inventory); + } + } + println!("# Unsupported content inventory\n"); + println!( + "{} distinct sections ({duplicates} identical copies skipped), {} pages, under {}.\n", + inventory.sections, + inventory.pages, + roots + .iter() + .map(|r| format!("`{}`", r.display())) + .collect::>() + .join(", ") + ); + let headings = [ + (Stage::Placeholder, "Drawn as a placeholder box"), + (Stage::ReadOnly, "Drawn as stored, read-only"), + ( + Stage::Refused, + "Edits refused as content the editor cannot edit", + ), + (Stage::Failure, "Does not open"), + ]; + for (stage, heading) in headings { + let mut rows: Vec<(&String, &Vec)> = inventory + .kinds + .iter() + .filter(|((s, _), _)| *s == stage) + .map(|((_, kind), places)| (kind, places)) + .collect(); + rows.sort_by(|a, b| b.1.len().cmp(&a.1.len()).then(a.0.cmp(b.0))); + println!("## {heading}\n"); + if rows.is_empty() { + println!("None.\n"); + continue; + } + println!("| Kind | Count | Pages | Examples |\n| --- | ---: | ---: | --- |"); + for (kind, places) in rows { + let pages: BTreeSet<&String> = places.iter().collect(); + let examples: Vec = pages.iter().take(3).map(|p| format!("`{p}`")).collect(); + println!( + "| {} | {} | {} | {} |", + kind.replace('|', "\\|"), + places.len(), + pages.len(), + examples.join("
").replace('|', "\\|") + ); + } + println!(); + } +} diff --git a/crates/canvas/examples/scratch_files.rs b/crates/canvas/examples/scratch_files.rs new file mode 100644 index 0000000000000000000000000000000000000000..6c458d6a182c00b8e003cf3e211a47fd58620915 --- /dev/null +++ b/crates/canvas/examples/scratch_files.rs @@ -0,0 +1,15 @@ +use onestore::{RevisionIndex, Store, document::{Document, Kind}}; +fn main() { + let bytes = std::fs::read(std::env::args().nth(1).unwrap()).unwrap(); + let store = Store::parse(&bytes).unwrap(); + let index = RevisionIndex::parse(&store).unwrap(); + let document = Document::parse(&index).unwrap(); + for (space, _) in document.pages().unwrap() { + let revision = document.active(space).unwrap(); + for (id, node) in &revision.nodes { + if let Kind::File { extension, payload, .. } = &node.kind { + println!("{id:?} {extension} {:?}", payload.map(|p| (p.len(), &p[..4.min(p.len())]))); + } + } + } +} diff --git a/crates/canvas/examples/scratch_runs.rs b/crates/canvas/examples/scratch_runs.rs new file mode 100644 index 0000000000000000000000000000000000000000..33b31e9ebba3048c62ffe441927688290c8187e5 --- /dev/null +++ b/crates/canvas/examples/scratch_runs.rs @@ -0,0 +1,23 @@ +use onestore::{Arena, Section, page::{PageObject}}; +fn main() { + let path = std::env::args().nth(1).unwrap(); + let want = std::env::args().nth(2).unwrap_or_default(); + let arena = Arena::default(); + let mut section = Section::open(&arena, std::fs::read(path).unwrap()).unwrap(); + for (space, _, _) in section.pages().unwrap() { + let page = section.page(space).unwrap(); + for object in &page.objects { + let PageObject::Outline(outline) = object else { continue }; + for p in &outline.paragraphs { + let Some(text) = p.text() else { continue }; + if !text.text.text().contains(want.as_str()) { continue } + let mut start = 0; + println!("-- {:?}", p.id); + for span in text.text.spans() { + println!(" {:?} math={:?} obj={:?} emb={:?}", &text.text.text()[start..span.end], span.format.math, span.format.math_object, span.format.embedded_object); + start = span.end; + } + } + } + } +} diff --git a/crates/canvas/src/editor.rs b/crates/canvas/src/editor.rs index e58c4651dbde740ddb90c48f358d46910c3811d5..e99e394f84450d108456ec3dac63641cc8b926b9 100644 --- a/crates/canvas/src/editor.rs +++ b/crates/canvas/src/editor.rs @@ -2178,39 +2178,29 @@ impl CanvasEditor { Ok(true) } - /// Puts `image` in the active outline's flow after the caret's paragraph, as OneNote - /// inserts a picture into an outline; the caret stays. + /// Puts `image` at the caret as OneNote 2010 pastes and inserts a picture: in an outline + /// as [`Self::insert_attachment`] puts a file, and on blank page at the caret with the + /// caret moving to the grid row below it, where typing starts a new outline. pub fn insert_picture( &mut self, engine: &mut TextEngine, - image: onestore::page::Image, + mut image: onestore::page::Image, ) -> Result<(), EditorError> { - let selection = self.selection(); - let caret = selection.positions[0].max(selection.positions[1]); - let (container, index, node) = self - .active_outline() - .document - .leaf(caret.paragraph) - .ok_or(EditError::InvalidRange)?; - let picture = PageParagraph { - id: onestore::page::text::new_id()?, - content: ParagraphContent::Image(image), - style: None, - lists: Vec::new(), - tags: Vec::new(), - collapsed: false, - ..node.clone() + let Focus::Caret { outline, .. } = &self.active else { + return self.insert_in_flow(engine, ParagraphContent::Image(image)); }; - self.commit( - engine, - DocumentEdit { - columns: BTreeMap::new(), - container, - range: index + 1..index + 1, - replacement: vec![picture], - }, - selection, - ) + let [x, y] = outline.origin(); + [image.layout.x, image.layout.y] = [Some(x), Some(y)]; + image.layout.width_set_by_user = Some(false); + let height = image.layout.max_height.unwrap_or_default(); + self.finish_composition(); + let index = self.objects.len(); + self.add_picture(index, image); + self.undo.push(History::Picture { index, image: None }); + self.redo.clear(); + let margin = self.margin_origin()[1]; + let row = ((y + height - margin) / 18.0).floor() + 1.0; + self.place_caret(engine, [x, margin + row * 18.0], DEFAULT_OUTLINE_WIDTH) } /// Attaches `file` at the caret as OneNote 2010 does (`corpus/attachment-insert`): the @@ -2241,11 +2231,21 @@ impl CanvasEditor { self.redo.clear(); return Ok(()); } - let file = match self.across(engine, |editor, engine| { - editor.insert_attachment(engine, file.clone()) + self.insert_in_flow(engine, ParagraphContent::Attachment(file)) + } + + /// Splits the caret's paragraph around `content`, which takes the place of an empty first + /// half; the caret starts the second. + fn insert_in_flow( + &mut self, + engine: &mut TextEngine, + content: ParagraphContent, + ) -> Result<(), EditorError> { + let content = match self.across(engine, |editor, engine| { + editor.insert_in_flow(engine, content.clone()) })? { Some(()) => return Ok(()), - None => file, + None => content, }; let [anchor, focus] = self.selection().positions; let (start, end) = (anchor.min(focus), anchor.max(focus)); @@ -2260,7 +2260,7 @@ impl CanvasEditor { }; let node = PageParagraph { id: onestore::page::text::new_id()?, - content: ParagraphContent::Attachment(file), + content, style: None, lists: Vec::new(), tags: Vec::new(), @@ -3209,6 +3209,7 @@ impl CanvasEditor { engine: &mut TextEngine, replacement: Vec, ) -> Result<(), EditorError> { + self.take_objects()?; let start = self.active_outline().selection.positions[0] .min(self.active_outline().selection.positions[1]); let end = self.active_outline().selection.positions[0] @@ -3308,6 +3309,7 @@ impl CanvasEditor { editor.paste(engine, text, language) }); } + self.take_objects()?; let lines = text .split('\n') .map(|line| line.strip_suffix('\r').unwrap_or(line)) @@ -3569,6 +3571,7 @@ impl CanvasEditor { self.grouped(|editor| editor.remove_page(engine, false))?; return Ok(true); } + self.take_objects()?; let selection = self.active_outline().selection; let [anchor, focus] = selection.positions; let mut range = anchor.min(focus)..anchor.max(focus); diff --git a/crates/canvas/src/editor/equation.rs b/crates/canvas/src/editor/equation.rs index 57b55a8cddb86b51d06ad84623b1114a07f18fb7..d76775c96e8565819d09180990165e5eeb9cffe2 100644 --- a/crates/canvas/src/editor/equation.rs +++ b/crates/canvas/src/editor/equation.rs @@ -36,6 +36,107 @@ pub(crate) fn zone(text: &Paragraph, offset: u32) -> Option> { current.filter(|zone| zone.start <= offset && offset <= zone.end) } +/// An object of an equation holding a position: its range, from its opening control to past +/// its closing one, and the argument the position lies in. +#[derive(PartialEq)] +struct Holder { + range: Range, + argument: usize, + placeholder: bool, +} + +/// The objects of `text` holding UTF-16 `offset` strictly inside, outermost first. +fn holders(text: &Paragraph, offset: u32) -> Vec { + // Each object's range and whether it is a placeholder; open objects and held ones by + // index, with the argument reached. + let mut objects: Vec<(Range, bool)> = Vec::new(); + let (mut open, mut held) = (Vec::new(), None); + let mut unit = 0; + for c in text.text().chars() { + if unit == offset { + held = Some(open.clone()); + } + match c { + OBJECT_START => { + // An equation's empty placeholder, "Type equation here.", is a box OneNote + // marks with this symbol. + let placeholder = text.format_at(unit + 1).is_ok_and(|format| { + format + .math_object + .as_ref() + .is_some_and(|object| object.kind == 11 && object.symbols == ['⬚']) + }); + open.push((objects.len(), 0)); + objects.push((unit..unit, placeholder)); + } + ARGUMENT_SEPARATOR => { + if let Some((_, argument)) = open.last_mut() { + *argument += 1; + } + } + OBJECT_END => { + if let Some((index, _)) = open.pop() { + objects[index].0.end = unit + 1; + } + } + _ => {} + } + unit += c.len_utf16() as u32; + } + held.unwrap_or(open) + .into_iter() + .map(|(index, argument)| Holder { + range: objects[index].0.clone(), + argument, + placeholder: objects[index].1, + }) + .collect() +} + +/// `range` as OneNote 2010's equation editor selects it (`corpus/equation-select`): an end +/// inside an object not holding the other end in the same argument takes the whole object, as +/// does an end inside a placeholder, and across paragraphs an object so taken at the end of +/// its paragraph takes the paragraph's end with it. +pub(crate) fn widen( + document: &TextDocument, + range: Range, +) -> Result, EditError> { + let text = |paragraph| document.paragraph(paragraph).ok_or(EditError::InvalidRange); + let last = text(range.end.paragraph)?; + let starts = holders(text(range.start.paragraph)?, range.start.offset); + let ends = holders(last, range.end.offset); + let common = if range.start.paragraph == range.end.paragraph { + starts.iter().zip(&ends).take_while(|(a, b)| a == b).count() + } else { + 0 + }; + let level = |holders: &[Holder]| { + holders + .iter() + .position(|holder| holder.placeholder) + .map_or(common, |placeholder| placeholder.min(common)) + }; + let mut widened = range.clone(); + if let Some(holder) = starts.get(level(&starts)) { + widened.start.offset = holder.range.start; + } + if let Some(holder) = ends.get(level(&ends)) { + widened.end.offset = holder.range.end; + let next = range.end.paragraph + 1; + let container = |paragraph| document.leaf(paragraph).map(|(container, ..)| container); + if range.start.paragraph != range.end.paragraph + && widened.end.offset == last.utf16_offset(last.text().len())? + && container(next).is_some_and(|next| Some(next) == container(range.end.paragraph)) + { + widened.end = TextPosition { + paragraph: next, + offset: 0, + }; + } + } + Ok(widened) +} + /// The format text typed after an equation in `text` takes: the paragraph's last text's, or /// its first run's without the equation editor's. pub(super) fn text_after(text: &Paragraph) -> Format { @@ -70,6 +171,20 @@ impl CanvasEditor { Some((caret.paragraph, zone(text, caret.offset)?)) } + /// Widens the selection an edit is about to replace as the equation editor selects. + pub(super) fn take_objects(&mut self) -> Result<(), EditError> { + let [anchor, focus] = self.active_outline().selection.positions; + let range = anchor.min(focus)..anchor.max(focus); + let widened = widen(&self.active_outline().document, range.clone())?; + if widened != range { + self.active_outline_mut().selection = Selection { + positions: [widened.start, widened.end], + affinities: [Affinity::Downstream, Affinity::Upstream], + }; + } + Ok(()) + } + /// Whether the caret is in an equation, which Linear and Professional act on. pub fn in_equation(&self) -> bool { self.caret_zone().is_some() @@ -373,13 +488,10 @@ impl CanvasEditor { for part in parts { broken.append(part)?; } - let Some(linear) = Math::parse(&broken) - .ok() - .and_then(|nodes| Math::linear(&nodes)) - else { + let Ok(nodes) = Math::parse(&broken) else { return Ok(false); }; - let built = Math::paragraph(&Math::from_linear(&linear), &math.spans()[0].format); + let built = Math::paragraph(&nodes, &math.spans()[0].format); // The caret starts the new row: after as many characters other than spaces as came // before it. let before = broken diff --git a/crates/canvas/src/editor/table.rs b/crates/canvas/src/editor/table.rs index bfaf7e654e54211ab74c6d7a4998d0ec74b36325..54bdaed6ce298322c513d0ed0510601196f002e2 100644 --- a/crates/canvas/src/editor/table.rs +++ b/crates/canvas/src/editor/table.rs @@ -398,6 +398,7 @@ impl CanvasEditor { if soft { return self.insert(engine, "\u{000b}"); } + self.take_objects()?; if self.active_outline().title { return self.leave_title(engine); } diff --git a/crates/canvas/src/gpu/mod.rs b/crates/canvas/src/gpu/mod.rs index 8a3e7579f7f85a85dda0e737e224e533d31e67e3..5bce91c1880590db8e3b5b83f9e5fba175b22f6c 100644 --- a/crates/canvas/src/gpu/mod.rs +++ b/crates/canvas/src/gpu/mod.rs @@ -110,6 +110,7 @@ impl Glyphs for TextLayout { }; draw::paint_parley_run( &run, + &self.text, bounds.baseline, run.style().brush.rise, [bounds.top, bounds.height], diff --git a/crates/canvas/src/gpu/page.rs b/crates/canvas/src/gpu/page.rs index 72952fc0b0caaa3d635135fbdef07b760bd49749..dcbef897c20d30ccf14cb64e54bf1526b6bab70a 100644 --- a/crates/canvas/src/gpu/page.rs +++ b/crates/canvas/src/gpu/page.rs @@ -766,6 +766,91 @@ impl PageScene { None } + /// Where the page read without an editor lies, in page coordinates: the rectangle all + /// its content covers, and the top and bottom of each line of text and each picture, which + /// a sheet of paper does not cut through where it can help it. + pub(crate) fn printed_extent(&self) -> Result<([f32; 4], Vec<[f32; 2]>), SceneError> { + let mut bounds = [ + f32::INFINITY, + f32::INFINITY, + f32::NEG_INFINITY, + f32::NEG_INFINITY, + ]; + let mut rows = Vec::new(); + let mut cover = |[x0, y0, x1, y1]: [f32; 4], row: bool| { + bounds = [ + bounds[0].min(x0), + bounds[1].min(y0), + bounds[2].max(x1), + bounds[3].max(y1), + ]; + if row { + rows.push([y0, y1]); + } + }; + for content in self.objects(None)? { + match content { + Content::Outline { + source, + layout, + below_title, + } => { + let [x, y] = outline_origin( + [ + source.layout.x.unwrap_or(0.0), + source.layout.y.unwrap_or(0.0), + ], + *below_title, + None, + )?; + cover([x, y, x + layout.size[0], y + layout.size[1]], false); + for paragraph in &layout.paragraphs { + let [px, py] = [x + paragraph.origin[0], y + paragraph.origin[1]]; + for (line, bounds) in paragraph.text.lines() { + let top = py + bounds.top; + let right = px + line.metrics().advance; + cover([px, top, right, top + bounds.height], true); + } + } + for object in &layout.objects { + let [x0, y0, x1, y1] = object.rect; + cover([x + x0, y + y0, x + x1, y + object.bottom.max(y1)], true); + } + } + Content::Image(source) => { + let [x, y] = [ + source.layout.x.unwrap_or(0.0), + source.layout.y.unwrap_or(0.0), + ]; + let size = match self.backgrounds.get(&source.id) { + Some(art) => Some(art.size), + None => source + .layout + .max_width + .zip(source.layout.max_height) + .map(|(width, height)| [width, height]), + }; + if let Some([width, height]) = size { + cover([x, y, x + width, y + height], !source.background); + } + } + Content::File { .. } => { + if let Some((_, rect)) = content.file() { + cover(rect, true); + } + } + Content::Ink(ink) => { + if let Some(rect) = crate::editor::page::ink_bounds(ink) { + cover(rect, false); + } + } + Content::ReadOnly(object) => cover(object.rect(), true), + Content::Date { .. } | Content::Editable(_) => {} + } + } + Ok((bounds, rows)) + } + /// The offset is in document points. pub fn append_primitives<'a>( &'a self, diff --git a/crates/canvas/src/interaction/ink.rs b/crates/canvas/src/interaction/ink.rs index 706a37c19cd33eca883d34fb31386c1cd1464017..ec8d621dfbd1fa456892bb6bcbc9365bd50b2499 100644 --- a/crates/canvas/src/interaction/ink.rs +++ b/crates/canvas/src/interaction/ink.rs @@ -2,7 +2,7 @@ //! dragged out on the grid, the stroke eraser, and the lasso whose drawings move and delete, //! as OneNote 2010 has them (`corpus/ink-tools`). -use super::{PageView, Response, Result, snap_to_grid}; +use super::{PageView, Response, Result}; use crate::editor::{FAVORITES, Pen}; use crate::gpu::colorref; use draw::{ @@ -184,14 +184,6 @@ impl PageView { Ok(Some(self.changed()?)) } - fn grid(&self, point: [f32; 2]) -> [f32; 2] { - if self.modifiers.option { - point - } else { - snap_to_grid(point, self.editor.margin_origin()) - } - } - /// The pointer moved to page point `point` during a gesture. pub(super) fn ink_moved(&mut self, point: [f32; 2]) -> Result { let pressure = self.ink.pressure; diff --git a/crates/canvas/src/interaction/mod.rs b/crates/canvas/src/interaction/mod.rs index 5ce5301ccc8a135d98d4a080a4fc8b8fbde34b20..7593d0281772abb4c6d65be2ed42fe7764e41383 100644 --- a/crates/canvas/src/interaction/mod.rs +++ b/crates/canvas/src/interaction/mod.rs @@ -258,6 +258,9 @@ pub struct PageView { /// A platform scroll view owns the viewport: changes neither clamp it nor reveal the /// caret, which the host does knowing its bars and keyboard. pub host_viewport: bool, + /// OneNote's Snap to Grid: clicks, drags and shapes land on the placement grid unless + /// Option (Alt) is held. Off, they land where the pointer is. + pub snap_to_grid: bool, /// Matches of the search shown on the page, marked under their text. pub found: Vec, /// The note playing, highlighted as See Playback highlights it. @@ -271,6 +274,9 @@ pub struct PageView { /// When the caret last moved, which restarts its blink. blink_from: Instant, ink: ink::State, + /// What the view showed before each zoom since the page opened, in document points: + /// scrolling still reaches it, so a zoom keeps the point under the pointer in place. + reach: Option<[f32; 4]>, } /// Room, in OneNote pixels, the view leaves beyond content it scrolls to. @@ -326,6 +332,7 @@ impl PageView { focused: true, touch: false, host_viewport: false, + snap_to_grid: true, found: Vec::new(), played: None, spelling: None, @@ -333,6 +340,7 @@ impl PageView { caret: 1.0, blink_from: Instant::now(), ink: Default::default(), + reach: None, }; view.place_opened(); view @@ -376,6 +384,7 @@ impl PageView { place: Option, ) { self.replace(editor, scene); + self.reach = None; let Some(place) = place else { return self.place_opened(); }; @@ -461,14 +470,7 @@ impl PageView { } let point = self.viewport.document_point(self.pointer); let position = [point[0] - grab[0], point[1] - grab[1]]; - Some(( - *id, - if self.modifiers.option { - position - } else { - snap_to_grid(position, self.editor.margin_origin()) - }, - )) + Some((*id, self.grid(position))) } /// The dragged outline and how far it would move. @@ -505,12 +507,16 @@ impl PageView { return Some((*id, origin, size)); } let origin = [origin[0] + delta[0], origin[1] + delta[1]]; - let origin = if self.modifiers.option { - origin + Some((*id, self.grid(origin), size)) + } + + /// `point` on the placement grid, where Snap to Grid is on and Option isn't held. + fn grid(&self, point: [f32; 2]) -> [f32; 2] { + if self.snap_to_grid && !self.modifiers.option { + snap_to_grid(point, self.editor.margin_origin()) } else { - snap_to_grid(origin, self.editor.margin_origin()) - }; - Some((*id, origin, size)) + point + } } fn pixel(&self) -> f32 { @@ -786,14 +792,27 @@ impl PageView { self.moved() } - /// Scales the view by `factor` about the pointer, as a trackpad pinch does. - pub fn pinch(&mut self, factor: f32) -> Result { - self.zoom_about(factor, self.pointer); + /// Scales the view by `factor` about `anchor`, in device pixels from the view's + /// top-left, as a trackpad pinch does about the pointer. + pub fn pinch(&mut self, factor: f32, anchor: [f32; 2]) -> Result { + self.zoom_about(factor, anchor); self.moved() } /// Scales the view by `factor`, keeping the document point under `anchor` in place. fn zoom_about(&mut self, factor: f32, anchor: [f32; 2]) { + let [x0, y0] = self.viewport.document_point([0.0; 2]); + let [x1, y1] = self + .viewport + .document_point(self.viewport.size.map(|size| size as f32)); + self.reach = Some(self.reach.map_or([x0, y0, x1, y1], |reach| { + [ + reach[0].min(x0), + reach[1].min(y0), + reach[2].max(x1), + reach[3].max(y1), + ] + })); let point = self.viewport.document_point(anchor); let dpr = self.display_scale; self.viewport.scale = (self.viewport.scale * factor).clamp(dpr / 3.0, dpr * 16.0 / 3.0); @@ -841,7 +860,16 @@ impl PageView { ) }) }); - scroll::Scroll::new(self.viewport, editable.map(|rect| (rect, pad)).chain(fixed)) + let mut scroll = + scroll::Scroll::new(self.viewport, editable.map(|rect| (rect, pad)).chain(fixed)); + if let Some(reach) = self.reach { + for axis in 0..2 { + scroll.min[axis] = scroll.min[axis].min(reach[axis] * self.viewport.scale); + scroll.max[axis] = scroll.max[axis] + .max(reach[axis + 2] * self.viewport.scale - self.viewport.size[axis] as f32); + } + } + scroll } /// Scrolls the view's corner `offset` device pixels from the page origin along `axis`, @@ -1263,11 +1291,7 @@ impl PageView { /// A fresh click places text 7 px above the pointer, on the grid. fn place_caret(&mut self, point: [f32; 2]) -> Result<()> { let position = [point[0], point[1] - 7.0 * self.pixel()]; - let position = if self.modifiers.option { - position - } else { - snap_to_grid(position, self.editor.margin_origin()) - }; + let position = self.grid(position); self.editor .place_caret(&mut self.engine, position, DEFAULT_OUTLINE_WIDTH)?; Ok(()) @@ -1662,7 +1686,8 @@ impl PageView { self.edited() } - /// Insert, Picture: a PNG, JPEG or GIF `size` points large after the caret's paragraph. + /// Insert, Picture, or a pasted one: a PNG, JPEG or GIF `size` points large; see + /// [`CanvasEditor::insert_picture`]. pub fn insert_picture(&mut self, bytes: Vec, size: [f32; 2]) -> Result { if !self.accepts_text() || self.editor.marked_range().is_some() { return Ok(Response::default()); @@ -1682,6 +1707,7 @@ impl PageView { printout: None, }; self.editor.insert_picture(&mut self.engine, image)?; + self.follow_pictures()?; self.edited() } @@ -2269,7 +2295,7 @@ fn page_hit( /// The page's rule lines over `visible`, a document rectangle, as OneNote 2010 draws them: /// 1/96 inch wide, or a device pixel where that is wider, horizontal lines from the margin /// origin down, and a grid's vertical lines through it or a margin line 1/96 inch left of it. -fn rule_primitives( +pub(crate) fn rule_primitives( lines: Option, [x, y]: [f32; 2], [left, top, right, bottom]: [f32; 4], diff --git a/crates/canvas/src/interaction/tests.rs b/crates/canvas/src/interaction/tests.rs index e33c5f3c08083621e588a55dca172bb8a116ab15..7d0e57ba3ed8231938cc7104d0150757ce26f2b6 100644 --- a/crates/canvas/src/interaction/tests.rs +++ b/crates/canvas/src/interaction/tests.rs @@ -1753,6 +1753,12 @@ fn events_route_through_the_view_as_the_host_delivers_them() { click(&mut view, [400.0, 300.0], now + Duration::from_secs(3)); let caret = view.editor.caret_outline().unwrap().origin(); assert_eq!(caret, snap_to_grid([400.0, 293.0], [36.0, 14.4])); + + // With Snap to Grid off it lands where the pointer is, as OneNote 2010 places it. + view.snap_to_grid = false; + click(&mut view, [410.0, 330.0], now + Duration::from_secs(5)); + let caret = view.editor.caret_outline().unwrap().origin(); + assert_eq!(caret, [410.0, 323.0]); } #[test] @@ -2471,6 +2477,8 @@ fn the_page_selection_does_not_return_with_its_text_selection() { assert_eq!(view.editor.whole(), None); } +/// The point under the pointer stays put through a pinch, as in Safari, even where the +/// page's content is too small to scroll that far; scrolling afterwards still reaches it. #[test] fn pinch_zooms_about_the_pointer_within_range() { let mut engine = TextEngine::default(); @@ -2488,17 +2496,28 @@ fn pinch_zooms_about_the_pointer_within_range() { 1.0, Duration::from_millis(500), ); - // The host's own scrolling leaves the anchor unclamped, as iOS's does. - view.host_viewport = true; - let pointer = [300.0, 200.0]; - let _ = view.pointer_moved(pointer).unwrap(); + let pointer = [700.0, 500.0]; let under = view.viewport.document_point(pointer); + let shown = view.viewport.document_point([800.0, 600.0]); + let stays = |view: &PageView| { + let after = view.viewport.document_point(pointer); + assert!( + (after[0] - under[0]).abs() < 1e-3 && (after[1] - under[1]).abs() < 1e-3, + "{under:?} moved to {after:?}" + ); + }; let zoom = view.zoom(); - assert!(view.pinch(1.5).unwrap().moved); - assert!((view.zoom() / zoom - 1.5).abs() < 1e-5); - let after = view.viewport.document_point(pointer); - assert!((after[0] - under[0]).abs() < 1e-3 && (after[1] - under[1]).abs() < 1e-3); - let _ = view.pinch(100.0).unwrap(); + for factor in [1.05, 1.0 / 1.05, 1.05] { + for _ in 0..10 { + assert!(view.pinch(factor, pointer).unwrap().moved); + stays(&view); + } + } + assert!((view.zoom() / zoom - 1.05_f32.powi(10)).abs() < 1e-4); + let _ = view.wheel([-5000.0; 2]).unwrap(); + let corner = view.viewport.document_point([800.0, 600.0]); + assert!((corner[0] - shown[0]).abs() < 1e-3 && (corner[1] - shown[1]).abs() < 1e-3); + let _ = view.pinch(100.0, pointer).unwrap(); assert!((view.zoom() - 4.0).abs() < 1e-5); } diff --git a/crates/canvas/src/layout.rs b/crates/canvas/src/layout.rs index 3f6f40114280f49b46e608687695dee5652ae0c6..2bccd6e2fa920c5da1291838b19baa9635f3dbfb 100644 --- a/crates/canvas/src/layout.rs +++ b/crates/canvas/src/layout.rs @@ -61,6 +61,8 @@ pub struct LineBox { pub struct TextLayout { id: u64, pub(crate) shaped: Arc>, + /// The paragraph text laid out, which a PDF's text layer maps glyphs back to. + pub(crate) text: Arc, lines: Vec, /// Where each inline space lies: its index in the spaces laid out, its x, and its line. spaces: Vec<(usize, f32, usize)>, @@ -518,6 +520,7 @@ impl TextEngine { Ok(TextLayout { id, shaped: Arc::new(shaped), + text: text.into(), lines, spaces: placed, }) diff --git a/crates/canvas/src/lib.rs b/crates/canvas/src/lib.rs index 8027f0e2606e64a4e0d3dfaf146810a907fc04c9..de0389776bb173090782f64dc8f19dd22381a50c 100644 --- a/crates/canvas/src/lib.rs +++ b/crates/canvas/src/lib.rs @@ -14,6 +14,8 @@ pub mod date; pub mod gpu; #[cfg(feature = "interaction")] pub mod interaction; +#[cfg(feature = "pdf")] +pub mod print; /// Parley's caret affinity mapped onto the page model's hidden-field affinity. pub fn affinity(affinity: parley::Affinity) -> onestore::page::text::Affinity { diff --git a/crates/canvas/src/print.rs b/crates/canvas/src/print.rs new file mode 100644 index 0000000000000000000000000000000000000000..02692d56d346f706170cd6fc2d51001b73872295 --- /dev/null +++ b/crates/canvas/src/print.rs @@ -0,0 +1,553 @@ +//! Pages on sheets of paper as OneNote 2010 prints them and saves them as PDF. +//! +//! OneNote draws a page between half-inch top and bottom margins, the page's margin origin +//! an inch from the paper's left edge and at the top margin, shrinking the whole page +//! when its content reaches past the paper's right edge ("Scale content to paper width"). +//! A page longer than a sheet continues on the next, which starts at the first line of text +//! or picture the sheet's foot would have cut. Rule lines and template art print across the +//! paper's width; the page colour does not. Each sheet's footer names the section and +//! numbers the sheet, counting from the first page printed, in Times New Roman. + +use crate::gpu::{Paper, page::PageScene}; +use crate::layout::{LayoutError, TextEngine}; +use draw::{Layer, Primitive, RenderError, Sheet}; +use onestore::page::{Page, text::Paragraph}; +use std::fmt; + +pub const LETTER: [f32; 2] = [612.0, 792.0]; +pub const A4: [f32; 2] = [595.276, 841.89]; + +/// The paper's top and bottom margins, where no page content prints. +const MARGIN: f32 = 36.0; +/// How far from the paper's left edge the margin origin prints at full size. +const LEFT: f32 = 72.0; +/// The room OneNote leaves right of the content when it shrinks a page to the paper's width. +const RIGHT: f32 = 9.0; +/// Pixels per point pictures are decoded at, 300 a inch. +const DENSITY: f32 = 300.0 / 72.0; + +/// How a page lies on its sheets. +struct Pagination { + /// Paper points per page point. + scale: f32, + /// The page x at the paper's left edge. + left: f32, + /// Where each sheet starts down the page. + tops: Vec, + /// How much of the page a sheet holds, in page points. + band: f32, +} + +impl Pagination { + /// Lays content covering `bounds`, whose `rows` (lines of text, pictures) no sheet + /// should cut, on `paper` from the page's `margin_origin`. + fn new( + bounds: [f32; 4], + rows: &[[f32; 2]], + margin_origin: [f32; 2], + paper: [f32; 2], + ) -> Self { + let left = margin_origin[0] - LEFT; + let scale = if bounds[2].is_finite() { + (paper[0] / (bounds[2] - left + RIGHT)).min(1.0) + } else { + 1.0 + }; + let band = (paper[1] - 2.0 * MARGIN) / scale; + let first = if bounds[1].is_finite() { + margin_origin[1].min(bounds[1]) + } else { + margin_origin[1] + }; + let bottom = bounds[3].max(first); + let mut tops = vec![first]; + let mut top = first; + while top + band < bottom { + // Moves the cut up to the top of whatever it would cross, until nothing shorter + // than a sheet crosses it. + let mut cut = top + band; + while let Some(row) = rows.iter().find(|[start, end]| { + *start < cut && *end > cut && *start > top + 1.0 && end - start <= band + }) { + cut = row[0]; + } + tops.push(cut); + top = cut; + } + Self { + scale, + left, + tops, + band, + } + } + + /// Each sheet's rows of the page, top and bottom: to where the next sheet starts, or + /// the paper's bottom margin on the last. + fn sheets(&self) -> impl Iterator + '_ { + self.tops.iter().enumerate().map(|(at, top)| { + [ + *top, + self.tops.get(at + 1).copied().unwrap_or(top + self.band), + ] + }) + } +} + +#[derive(Debug)] +pub enum PrintError { + Scene(crate::gpu::page::SceneError), + Layout(LayoutError), + Render(RenderError), +} + +impl fmt::Display for PrintError { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Scene(error) => write!(formatter, "The page could not be laid out: {error}"), + Self::Layout(error) => write!(formatter, "The footer could not be laid out: {error:?}"), + Self::Render(error) => write!(formatter, "The PDF could not be written: {error:?}"), + } + } +} + +impl std::error::Error for PrintError {} + +/// `pages` in order as a PDF on `paper` (points), each on as many sheets as it takes, the +/// footers naming `section`. +pub fn pdf( + pages: Vec, + engine: &mut TextEngine, + paper: [f32; 2], + section: &str, +) -> Result, PrintError> { + let title = pages + .first() + .map(|page| page.title.clone()) + .unwrap_or_default(); + let mut printed = Vec::with_capacity(pages.len()); + for page in pages { + let (margin_origin, rules) = (page.margin_origin, page.rule_lines); + let mut scene = PageScene::new(page, engine).map_err(PrintError::Scene)?; + scene.settle(None, DENSITY, Paper::WHITE); + let (bounds, rows) = scene.printed_extent().map_err(PrintError::Scene)?; + let pagination = Pagination::new(bounds, &rows, margin_origin, paper); + printed.push((scene, pagination, margin_origin, rules)); + } + let mut contents = Vec::with_capacity(printed.len()); + for (scene, pagination, margin_origin, rules) in &printed { + let mut primitives = Vec::new(); + scene + .append_primitives(&mut primitives, [0.0; 2], Paper::WHITE) + .map_err(PrintError::Scene)?; + let rules: Vec<_> = pagination + .sheets() + .map(|[top, _]| { + let right = pagination.left + paper[0] / pagination.scale; + crate::interaction::rule_primitives( + *rules, + *margin_origin, + [pagination.left, top, right, top + pagination.band], + 0.0, + Paper::WHITE, + ) + }) + .collect(); + contents.push((primitives, rules)); + } + let format = onestore::document::Format { + font: Some("Times New Roman".into()), + font_size: Some(10.0), + ..Default::default() + }; + let mut footers = Vec::new(); + for (sheet, _) in printed + .iter() + .flat_map(|(_, pagination, ..)| pagination.sheets()) + .enumerate() + { + let text = match section { + "" => format!("Page {}", sheet + 1), + section => format!("{section} Page {}", sheet + 1), + }; + let layout = engine + .layout(&Paragraph::new(text, format.clone()), f32::MAX) + .map_err(PrintError::Layout)?; + footers.push(layout); + } + let footer_primitives: Vec<_> = footers + .iter() + .map(|layout| { + let (line, bounds) = layout.lines().next().expect("A laid-out footer has a line"); + [Primitive::Text { + text: layout, + origin: [-line.metrics().advance / 2.0, -bounds.baseline], + clip: None, + ink: Paper::WHITE.ink, + }] + }) + .collect(); + let mut sheets = Vec::new(); + let mut footer = footer_primitives.iter(); + for ((_, pagination, ..), (primitives, rules)) in printed.iter().zip(&contents) { + let scale = pagination.scale; + for ([top, bottom], rules) in pagination.sheets().zip(rules) { + let origin = [-pagination.left * scale, MARGIN - top * scale]; + // Rule lines run to the bottom margin, the page's content to where the next + // sheet takes it up. + let page = |primitives, bottom: f32| Layer { + scale, + origin, + clip: Some([0.0, MARGIN, paper[0], MARGIN + (bottom - top) * scale]), + backdrop: None, + round: None, + motion: None, + primitives, + }; + // OneNote shrinks the footer with the page, towards the paper's bottom left. + let footer = Layer { + scale, + origin: [ + paper[0] / 2.0 * scale, + paper[1] - 2.0 - (1.0 - scale) * 16.0, + ], + clip: None, + backdrop: None, + round: None, + motion: None, + primitives: footer.next().expect("Each sheet has a footer"), + }; + sheets.push(Sheet { + size: paper, + layers: vec![ + page(rules, top + pagination.band), + page(primitives, bottom), + footer, + ], + }); + } + } + draw::pdf(&title, &sheets).map_err(PrintError::Render) +} + +#[cfg(test)] +mod tests { + use super::*; + use onestore::{RevisionIndex, Store, document::Document}; + use std::collections::HashMap; + + fn section(path: &str) -> Vec { + let bytes = std::fs::read(format!("{}/../../{path}", env!("CARGO_MANIFEST_DIR"))).unwrap(); + let store = Store::parse(&bytes).unwrap(); + let index = RevisionIndex::parse(&store).unwrap(); + let document = Document::parse(&index).unwrap(); + let mut spaces: Vec<_> = document + .pages() + .unwrap() + .into_iter() + .map(|(space, _)| space) + .collect(); + spaces.dedup(); + spaces + .into_iter() + .map(|space| Page::from_space(&document, space).unwrap()) + .collect() + } + + /// Each sheet's size and text, as a reader extracts it through the fonts' ToUnicode maps. + fn sheets(pdf: &[u8]) -> Vec<([f32; 2], String)> { + let find = |haystack: &[u8], needle: &[u8]| { + haystack + .windows(needle.len()) + .position(|window| window == needle) + }; + let mut objects: HashMap)> = HashMap::new(); + let mut rest = pdf; + while let Some(start) = find(rest, b" 0 obj\n") { + let number = rest[..start] + .rsplit(|byte| !byte.is_ascii_digit()) + .next() + .unwrap(); + let number: u32 = std::str::from_utf8(number).unwrap().parse().unwrap(); + rest = &rest[start + 7..]; + let end = find(rest, b"endobj").unwrap(); + let object = &rest[..end]; + let (dictionary, stream) = match find(object, b"stream\n") { + Some(at) => { + let data = &object[at + 7..find(object, b"\nendstream").unwrap()]; + ( + &object[..at], + miniz_oxide::inflate::decompress_to_vec_zlib(data).unwrap_or_default(), + ) + } + None => (object, Vec::new()), + }; + objects.insert(number, (dictionary, stream)); + rest = &rest[end..]; + } + let text = |bytes: &[u8]| String::from_utf8_lossy(bytes).into_owned(); + let reference = |dictionary: &[u8], key: &str| -> Option { + let dictionary = text(dictionary); + let at = dictionary.find(&format!("{key} "))? + key.len() + 1; + dictionary[at..].split(' ').next()?.parse().ok() + }; + let tree = objects + .values() + .find(|(dictionary, _)| text(dictionary).contains("/Type /Pages")) + .unwrap(); + let kids = text(tree.0); + let kids = &kids[kids.find("/Kids [").unwrap() + 7..]; + let kids: Vec = kids[..kids.find(']').unwrap()] + .split(" 0 R") + .filter_map(|kid| kid.trim().parse().ok()) + .collect(); + kids.into_iter() + .map(|page| { + let dictionary = text(objects[&page].0); + let media: Vec = dictionary[dictionary.find("/MediaBox [").unwrap() + 11..] + .split(']') + .next() + .unwrap() + .split_whitespace() + .map(|value| value.parse().unwrap()) + .collect(); + let mut maps: HashMap> = HashMap::new(); + for (at, _) in dictionary.match_indices("/F") { + let mut words = dictionary[at + 1..].split_whitespace(); + let (Some(name), Some(font)) = ( + words.next(), + words.next().and_then(|id| id.parse::().ok()), + ) else { + continue; + }; + let Some(unicode) = reference(objects[&font].0, "/ToUnicode") else { + continue; + }; + let cmap = text(&objects[&unicode].1); + let mut map = HashMap::new(); + for line in cmap.lines().filter(|line| line.starts_with('<')) { + let hex: Vec<&str> = line + .split(['<', '>', ' ']) + .filter(|part| !part.is_empty()) + .collect(); + let units: Vec = hex[1] + .as_bytes() + .chunks(4) + .map(|unit| { + u16::from_str_radix(std::str::from_utf8(unit).unwrap(), 16).unwrap() + }) + .collect(); + map.insert( + u16::from_str_radix(hex[0], 16).unwrap(), + String::from_utf16_lossy(&units), + ); + } + maps.insert(name.to_owned(), map); + } + let content = &objects[&reference(objects[&page].0, "/Contents").unwrap()].1; + let (mut shown, mut font, mut name, mut at) = + (String::new(), String::new(), String::new(), 0); + while at < content.len() { + let byte = content[at]; + at += 1; + let mut string = Vec::new(); + match byte { + b'(' => { + while content[at] != b')' { + if content[at] == b'\\' { + at += 1; + if content[at].is_ascii_digit() { + let octal = + std::str::from_utf8(&content[at..at + 3]).unwrap(); + string.push(u8::from_str_radix(octal, 8).unwrap()); + at += 3; + continue; + } + string.push(match content[at] { + b'n' => b'\n', + b'r' => b'\r', + b't' => b'\t', + b'b' => 8, + b'f' => 12, + other => other, + }); + } else { + string.push(content[at]); + } + at += 1; + } + at += 1; + } + b'<' if content[at] != b'<' => { + let end = + at + content[at..].iter().position(|byte| *byte == b'>').unwrap(); + string = content[at..end] + .chunks(2) + .map(|pair| { + u8::from_str_radix(std::str::from_utf8(pair).unwrap(), 16) + .unwrap() + }) + .collect(); + at = end + 1; + } + b'/' => { + let end = at + + content[at..] + .iter() + .position(|byte| byte.is_ascii_whitespace()) + .unwrap(); + name = text(&content[at..end]); + at = end; + } + b'T' if content.get(at) == Some(&b'f') => font = name.clone(), + b'T' if content.get(at) == Some(&b'm') => shown.push('\n'), + _ => {} + } + if let Some(map) = maps.get(&font) { + for cid in string.chunks(2).filter(|pair| pair.len() == 2) { + if let Some(text) = map.get(&u16::from_be_bytes([cid[0], cid[1]])) { + shown.push_str(text); + } + } + } + } + ([media[2], media[3]], shown) + }) + .collect() + } + + /// A ligature's glyph reads back as the letters it joins. + #[test] + fn glyphs_read_back_as_their_text() { + let mut engine = TextEngine::default(); + let format = onestore::document::Format { + font: Some("Calibri".into()), + font_size: Some(11.0), + ..Default::default() + }; + let layout = engine + .layout(&Paragraph::new("office fish ffi".into(), format), f32::MAX) + .unwrap(); + let primitives = [Primitive::Text { + text: &layout, + origin: [72.0, 72.0], + clip: None, + ink: Paper::WHITE.ink, + }]; + let sheet = Sheet { + size: LETTER, + layers: vec![Layer { + scale: 1.0, + origin: [0.0; 2], + clip: None, + backdrop: None, + round: None, + motion: None, + primitives: &primitives, + }], + }; + let pdf = draw::pdf("", &[sheet]).unwrap(); + assert_eq!(sheets(&pdf)[0].1.trim(), "office fish ffi"); + } + + #[test] + fn sheets_break_between_lines() { + // Lines 20 points tall from 90 down; a Letter sheet holds 720 points of page. + let rows: Vec<[f32; 2]> = (0..60) + .map(|line| [90.0 + line as f32 * 20.0, 110.0 + line as f32 * 20.0]) + .collect(); + let pagination = Pagination::new([36.0, 14.4, 400.0, 1290.0], &rows, [36.0, 14.4], LETTER); + assert_eq!(pagination.scale, 1.0); + // 14.4 + 720 cuts the line from 730 to 750, which starts the next sheet. + assert_eq!(pagination.tops, [14.4, 730.0]); + let sheets: Vec<_> = pagination.sheets().collect(); + assert_eq!(sheets, [[14.4, 730.0], [730.0, 1450.0]]); + } + + #[test] + fn a_line_taller_than_a_sheet_is_cut() { + let pagination = Pagination::new( + [36.0, 14.4, 400.0, 1000.0], + &[[20.0, 1000.0]], + [36.0, 14.4], + LETTER, + ); + assert_eq!(pagination.tops, [14.4, 734.4]); + } + + /// OneNote's scales for pages whose content ends 866.7, 581.8 and 1221.4 points across, + /// on its 612.36-point Letter sheet (`corpus/print`). + #[test] + fn wide_pages_shrink_to_the_paper_as_onenote_shrinks_them() { + for (right, onenote) in [ + (866.7, 0.67167), + (581.8, 0.978), + (1221.4, 0.48361), + (400.0, 1.0), + ] { + let scale = Pagination::new( + [36.0, 14.4, right, 100.0], + &[], + [36.0, 14.4], + [612.36, 790.92], + ) + .scale; + assert!( + (scale - onenote).abs() < 0.002, + "{right}: {scale} for {onenote}" + ); + } + } + + /// `corpus/print`: the section OneNote 2010 saved as `native/section.pdf`, on the + /// same sheets with the same text. + #[test] + fn a_section_prints_on_onenotes_sheets() { + let pdf = pdf( + section("corpus/print/native/Print.one"), + &mut TextEngine::default(), + LETTER, + "Print", + ) + .unwrap(); + let sheets = sheets(&pdf); + assert_eq!(sheets.len(), 5); + for (at, (size, text)) in sheets.iter().enumerate() { + assert_eq!(*size, LETTER); + assert!(text.contains(&format!("Print Page {}", at + 1)), "{text}"); + } + let [first, second] = [&sheets[0].1, &sheets[1].1]; + assert!(first.contains("Printing test")); + assert!( + first.contains( + "Line 37 of the long outline, with enough words to show wrapping where the" + ) + ); + assert!(first.contains("outline is narrow. Searchable-37")); + assert!(first.contains("Far right outline past the paper width")); + assert!(!first.contains("Searchable-38")); + assert!(second.contains("Line 38 of the long outline")); + assert!(second.contains("Searchable-70")); + assert!(!second.contains("Searchable-37\n")); + assert!(sheets[2].1.contains("Short second page")); + } + + /// `corpus/page-background`'s pages, ruled and with template art, take the twelve + /// sheets OneNote 2010 prints them on (`corpus/print/native/rules-section.pdf`), the + /// art reaching past the Very Large Grid page's first. + #[test] + fn ruled_pages_and_art_print_on_onenotes_sheets() { + let pdf = pdf( + section("corpus/page-background/candidate/Rules.one"), + &mut TextEngine::default(), + LETTER, + "Rules", + ) + .unwrap(); + let sheets = sheets(&pdf); + assert_eq!(sheets.len(), 12); + assert!(sheets[8].1.contains("VeryLargeGrid")); + assert!(sheets[9].1.contains("Rules Page 10")); + assert!(!sheets[9].1.contains("VeryLargeGrid")); + } +} diff --git a/crates/canvas/tests/links_equations.rs b/crates/canvas/tests/links_equations.rs index 7a76e09f8056b72dfc3d9b700f140ab484940337..0129c39e54a88eaf80dbc1dd7b760f9185d71152 100644 --- a/crates/canvas/tests/links_equations.rs +++ b/crates/canvas/tests/links_equations.rs @@ -797,3 +797,190 @@ fn equations_draw_inline_and_url_text_shows_as_a_link() { assert_eq!(canvas::editor::shown_urls(&url), vec![5..22]); assert!(url.spans()[0].format.hyperlink.is_none()); } + +/// Selections reaching into equation objects, and Enter in a placeholder and in a limit, act +/// as OneNote 2010's equation editor acted on the same page (`corpus/equation-select`): an +/// end inside an object the other end is outside takes the whole object, and across +/// paragraphs the end of the paragraph with it; a placeholder is taken whole; Enter inside a +/// limit makes its argument an equation array. Each action saves as one revision. +#[test] +fn selections_into_equation_objects_take_them_whole() { + let root = Path::new(env!("CARGO_MANIFEST_DIR")).join("../.."); + let source = + std::fs::read(root.join("corpus/math-edit/native-editor-4/notebook/links.one")).unwrap(); + let (space, page) = pages(&source).remove(0); + let mut engine = TextEngine::default(); + let engine = &mut engine; + let mut editor = CanvasEditor::from_page(page, engine).unwrap(); + let body = editor + .outlines() + .iter() + .find(|outline| !outline.title) + .unwrap() + .id; + editor.focus_outline(body).unwrap(); + let texts = |editor: &CanvasEditor| -> Vec { + editor + .active_outline() + .document() + .paragraphs() + .map(|text| text.text().to_owned()) + .collect() + }; + let original = texts(&editor); + let find = |editor: &CanvasEditor, needle: &str| { + let paragraph = texts(editor) + .iter() + .position(|text| text.contains(needle)) + .unwrap(); + let text = editor + .active_outline() + .document() + .paragraphs() + .nth(paragraph) + .unwrap() + .clone(); + TextPosition { + paragraph, + offset: text + .utf16_offset(text.text().find(needle).unwrap()) + .unwrap(), + } + }; + let arena = Arena::default(); + let mut section = Section::open(&arena, source).unwrap(); + let mut save = |editor: &mut CanvasEditor| { + let ops = editor + .take_ops() + .unwrap() + .into_iter() + .map(|op| onestore::op::Op::Page { space, op }) + .collect(); + section + .apply( + "Author", + &onestore::op::Edit { + at: 134_000_000_000_000_000, + ops, + }, + ) + .unwrap(); + section.seal().unwrap().unwrap(); + }; + let delete = |editor: &mut CanvasEditor, engine: &mut TextEngine, from, to| { + editor.select([from, to].into()).unwrap(); + assert!(editor.delete(engine, true).unwrap()); + }; + + // Enter in "Type equation here." leaves the placeholder's paragraph empty above a new one. + let placeholder = find(&editor, "equation here"); + select(&mut editor, placeholder.paragraph, placeholder.offset..placeholder.offset); + editor.enter(engine, false).unwrap(); + save(&mut editor); + let after = texts(&editor); + assert_eq!(after[placeholder.paragraph..=placeholder.paragraph + 1], ["", ""]); + assert_eq!(caret(&editor).paragraph, placeholder.paragraph + 1); + + // From inside a square root into a cube root: both paragraphs go whole. + let (from, to) = (find(&editor, "\u{fdef}+1"), find(&editor, "3\u{fdee}𝑥")); + let to = TextPosition { + offset: to.offset + 4, + ..to + }; + delete(&mut editor, engine, from, to); + save(&mut editor); + let mut expected = after.clone(); + expected.drain(from.paragraph..=to.paragraph); + assert_eq!(texts(&editor), expected); + + // From after a₁ into a sum: the sum goes whole with its paragraph's end, joining the + // integral below it. + let from = find(&editor, "+\u{fdd0}𝑏"); + let to = find(&editor, "𝑖 \u{fdef}"); + let to = TextPosition { + offset: to.offset + 2, + ..to + }; + delete(&mut editor, engine, from, to); + save(&mut editor); + assert_eq!( + texts(&editor)[from.paragraph], + "\u{fdd0}𝑎\u{fdee}1\u{fdef}\u{fdd0}0\u{fdee}1\u{fdee}𝑥 𝑑𝑥 \u{fdef}" + ); + + // Enter inside a limit's argument makes it an equation array. + let limit = find(&editor, "∞"); + select(&mut editor, limit.paragraph, limit.offset..limit.offset); + editor.enter(engine, false).unwrap(); + save(&mut editor); + assert!(texts(&editor)[limit.paragraph].contains("𝑛→\u{fdee}∞\u{fdef}")); + + // Text around equations: from a fraction's numerator into a root, both taken whole. + let end = texts(&editor).len() - 1; + let offset = editor + .active_outline() + .document() + .paragraphs() + .nth(end) + .unwrap() + .utf16_offset(texts(&editor)[end].len()) + .unwrap(); + select(&mut editor, end, offset..offset); + for (before, linear, after) in [("One ", "a/b+c ", " two"), ("Three ", "\\sqrt x+y ", " four")] { + typed(&mut editor, engine, before); + editor.insert_equation(engine).unwrap(); + typed(&mut editor, engine, linear); + editor + .move_selection(engine, draw::edit::Movement::Right, false) + .unwrap(); + typed(&mut editor, engine, after); + line(&mut editor, engine); + } + save(&mut editor); + let from = find(&editor, "𝑎\u{fdee}𝑏\u{fdef}+𝑐"); + let to = find(&editor, "𝑥\u{fdef}+𝑦"); + let (from, to) = ( + TextPosition { + offset: from.offset + 2, + ..from + }, + TextPosition { + offset: to.offset + 2, + ..to + }, + ); + delete(&mut editor, engine, from, to); + save(&mut editor); + let joined = &texts(&editor)[from.paragraph]; + assert!(joined.starts_with("One +𝑦"), "{joined:?}"); + assert!(joined.ends_with(" four"), "{joined:?}"); + + let written = section.image(); + let (_, stored) = pages(&written).remove(0); + let stored: Vec = stored + .objects + .iter() + .filter_map(|object| match object { + PageObject::Outline(outline) if !outline.title => Some(outline), + _ => None, + }) + .flat_map(|outline| &outline.paragraphs) + .filter_map(|paragraph| paragraph.text()) + .map(|text| text.text.text().to_owned()) + .collect(); + assert_eq!(stored, texts(&editor)); + if let Some(directory) = std::env::var_os("CANVAS_EQUATION_SELECT_EXPORT") { + let directory = std::path::PathBuf::from(directory); + std::fs::create_dir(&directory).unwrap(); + std::fs::write(directory.join("links.one"), &written).unwrap(); + let file_id = Store::parse(&written).unwrap().header.file_id; + std::fs::write( + directory.join("Open Notebook.onetoc2"), + onestore::create_table_of_contents("Open Notebook.onetoc2", &[("links.one", file_id)]) + .unwrap(), + ) + .unwrap(); + } + while editor.undo(engine).unwrap() {} + assert_eq!(texts(&editor), original); +} diff --git a/crates/canvas/tests/picture_paste.rs b/crates/canvas/tests/picture_paste.rs new file mode 100644 index 0000000000000000000000000000000000000000..940b40d8fe90a6a35efcf21a3692f84b99055feb --- /dev/null +++ b/crates/canvas/tests/picture_paste.rs @@ -0,0 +1,196 @@ +//! Pictures pasted or inserted through the editor, placed as OneNote 2010 places them (lab, +//! 2026-09-30): at a caret in text the paragraph splits around the picture, and at a caret +//! on blank page the picture lies on the page there with the caret on the grid row below. +//! Each is one edit and one undo step. `CANVAS_PICTURE_EXPORT` names a directory receiving +//! the section as a notebook, for a cold reopen in OneNote 2010. + +use canvas::{ + document::TextPosition, + editor::{CanvasEditor, Selection}, + layout::TextEngine, +}; +use onestore::{ + Arena, Section, Store, + document::Layout, + op::{Edit, Op}, + page::{Image, PageObject, ParagraphContent}, +}; +use parley::Affinity; + +fn picture(size: [f32; 2]) -> Image { + let mut png = Vec::new(); + image::RgbaImage::from_pixel(200, 100, image::Rgba([30, 144, 255, 255])) + .write_to(&mut std::io::Cursor::new(&mut png), image::ImageFormat::Png) + .unwrap(); + Image { + id: onestore::page::text::new_id().unwrap(), + layout: Layout { + max_width: Some(size[0]), + max_height: Some(size[1]), + ..Default::default() + }, + size: Some(size), + bytes: Some(png.into()), + display: None, + alt: None, + background: false, + printout: None, + } +} + +fn caret(paragraph: usize, offset: u32) -> Selection { + let position = TextPosition { paragraph, offset }; + Selection { + positions: [position; 2], + affinities: [Affinity::Downstream; 2], + } +} + +/// The body outline's paragraphs: text as itself, a picture as its size. +fn body(editor: &CanvasEditor) -> Vec { + let page = editor.page().unwrap(); + let outline = page + .objects + .iter() + .find_map(|object| match object { + PageObject::Outline(outline) if !outline.title => Some(outline), + _ => None, + }) + .unwrap(); + outline + .paragraphs + .iter() + .map(|paragraph| match ¶graph.content { + ParagraphContent::Text(text) => text.text.text().to_owned(), + ParagraphContent::Image(image) => format!("{:?}", image.size.unwrap()), + _ => panic!(), + }) + .collect() +} + +fn page_pictures(editor: &CanvasEditor) -> Vec { + editor + .page() + .unwrap() + .objects + .into_iter() + .filter_map(|object| match object { + PageObject::Image(image) if !image.background => Some(image), + _ => None, + }) + .collect() +} + +#[test] +fn pasted_pictures_split_the_text_or_lie_on_the_page_as_onenote_places_them() { + let source = onestore::create_section("pictures.one", "Pasted pictures", "Author").unwrap(); + let arena = Arena::default(); + let mut section = Section::open(&arena, source.clone()).unwrap(); + let (space, ..) = section.pages().unwrap()[0].clone(); + let mut engine = TextEngine::default(); + let mut editor = CanvasEditor::from_page(section.page(space).unwrap(), &mut engine).unwrap(); + let mut at = 133_000_000_000_000_000; + let mut store = |editor: &mut CanvasEditor| { + let ops = editor.take_ops().unwrap(); + assert!(!ops.is_empty()); + at += 10_000_000; + let ops = ops.into_iter().map(|op| Op::Page { space, op }).collect(); + section.apply("Author", &Edit { at, ops }).unwrap(); + }; + let text = editor + .outlines() + .iter() + .find(|outline| !outline.title) + .unwrap() + .id; + editor.focus_outline(text).unwrap(); + + // Within text, the caret starting the second half. + editor.select(caret(0, 6)).unwrap(); + editor + .insert_picture(&mut engine, picture([150.0, 75.0])) + .unwrap(); + store(&mut editor); + assert_eq!(body(&editor), ["Pasted", "[150.0, 75.0]", " pictures"]); + assert_eq!( + editor.selection().positions, + [TextPosition { + paragraph: 1, + offset: 0 + }; 2] + ); + editor.undo(&mut engine).unwrap(); + store(&mut editor); + assert_eq!(body(&editor), ["Pasted pictures"]); + + // At the end, an empty paragraph follows for the caret; at an empty paragraph's start + // the picture takes its place. + editor.select(caret(0, 15)).unwrap(); + editor + .insert_picture(&mut engine, picture([150.0, 75.0])) + .unwrap(); + store(&mut editor); + editor + .insert_picture(&mut engine, picture([200.0, 100.0])) + .unwrap(); + store(&mut editor); + assert_eq!( + body(&editor), + ["Pasted pictures", "[150.0, 75.0]", "[200.0, 100.0]", ""] + ); + + // On blank page: at the caret, the caret moving to the grid row below (OneNote put a + // 75 pt picture at y 266.4 and the caret at 356.4, a 72 pt one at 248.4 and 338.4). + for (y, height, below) in [(266.4, 75.0, 356.4), (248.4 + 180.0, 72.0, 338.4 + 180.0)] { + editor.place_caret(&mut engine, [270.0, y], 468.0).unwrap(); + editor + .insert_picture(&mut engine, picture([150.0, height])) + .unwrap(); + store(&mut editor); + let placed = page_pictures(&editor).pop().unwrap(); + assert_eq!([placed.layout.x, placed.layout.y], [Some(270.0), Some(y)]); + assert_eq!(editor.active_outline().origin(), [270.0, below]); + } + editor.insert(&mut engine, "below").unwrap(); + store(&mut editor); + editor.undo(&mut engine).unwrap(); + editor.undo(&mut engine).unwrap(); + store(&mut editor); + assert_eq!(page_pictures(&editor).len(), 1); + + let mut image = source; + section.seal().unwrap().unwrap().apply(&mut image).unwrap(); + let arena = Arena::default(); + let reopened = Section::open(&arena, image.clone()).unwrap(); + let page = reopened.page(space).unwrap(); + let stored: Vec<_> = page + .objects + .iter() + .filter_map(|object| match object { + PageObject::Image(image) => Some(image), + _ => None, + }) + .collect(); + assert_eq!(stored.len(), 1); + assert_eq!( + [stored[0].layout.x, stored[0].layout.y], + [Some(270.0), Some(266.4)] + ); + assert_eq!(*stored[0], page_pictures(&editor)[0]); + + if let Some(directory) = std::env::var_os("CANVAS_PICTURE_EXPORT") { + let directory = std::path::PathBuf::from(directory); + std::fs::create_dir_all(&directory).unwrap(); + std::fs::write(directory.join("pictures.one"), &image).unwrap(); + let file_id = Store::parse(&image).unwrap().header.file_id; + std::fs::write( + directory.join("Open Notebook.onetoc2"), + onestore::create_table_of_contents( + "Open Notebook.onetoc2", + &[("pictures.one", file_id)], + ) + .unwrap(), + ) + .unwrap(); + } +} diff --git a/crates/draw/Cargo.toml b/crates/draw/Cargo.toml index 571f2a3c0753d51db4bb8e725488bb32347bccb4..6e0ac70b2dbea62d7086e2e43cd55dc04c356a6b 100644 --- a/crates/draw/Cargo.toml +++ b/crates/draw/Cargo.toml @@ -11,6 +11,8 @@ default = ["wgpu"] # Windows 7 has no Direct3D 12. render = ["dep:base64", "dep:bytemuck", "dep:image", "dep:linebender_resource_handle", "dep:roxmltree", "dep:swash"] wgpu = ["render", "dep:wgpu"] +# Writes layers as PDF pages, text as real text in subset fonts. +pdf = ["render", "dep:miniz_oxide", "dep:pdf-writer", "dep:subsetter"] [dependencies] parley.workspace = true @@ -19,7 +21,10 @@ base64 = { version = "0.22.1", optional = true } bytemuck = { version = "1.25", features = ["derive"], optional = true } image = { version = "0.25", default-features = false, features = ["gif", "jpeg", "png", "tiff"], optional = true } linebender_resource_handle = { version = "0.1.1", optional = true } +miniz_oxide = { version = "0.8", optional = true } +pdf-writer = { version = "0.15", optional = true } roxmltree = { version = "0.21", optional = true } +subsetter = { version = "0.2.6", default-features = false, optional = true } swash = { version = "0.2.10", optional = true } wgpu = { workspace = true, optional = true } diff --git a/crates/draw/src/render.rs b/crates/draw/src/render.rs index 9ffeb1cd045adffae3d836421e9450fa5ebdaf3c..551e387be5a83c8d4606b97e8e801df5bc6f6c93 100644 --- a/crates/draw/src/render.rs +++ b/crates/draw/src/render.rs @@ -3,6 +3,8 @@ mod dual; #[cfg(any(windows, not(feature = "wgpu")))] mod gl; mod icon; +#[cfg(feature = "pdf")] +mod pdf; mod text; #[cfg(feature = "wgpu")] mod translucent; @@ -20,6 +22,8 @@ pub use backend::Target; #[cfg(all(feature = "wgpu", windows))] pub use gl::Target as GlTarget; pub use icon::{Palette, picture_icon}; +#[cfg(feature = "pdf")] +pub use pdf::{Sheet, pdf}; pub use text::{Decoration, Glyph, GlyphRun, Glyphs, paint_parley_run}; #[cfg(feature = "wgpu")] pub use translucent::Translucent; @@ -1736,6 +1740,7 @@ mod tests { if let PositionedLayoutItem::GlyphRun(run) = item { paint_parley_run( &run, + "", metrics.baseline, 0.0, [metrics.block_min_coord, metrics.line_height], diff --git a/crates/draw/src/render/pdf.rs b/crates/draw/src/render/pdf.rs new file mode 100644 index 0000000000000000000000000000000000000000..ab01d8fe5400740d90ec43617f1a83591ee01fcd --- /dev/null +++ b/crates/draw/src/render/pdf.rs @@ -0,0 +1,1004 @@ +//! Layers written as the sheets of a PDF: glyphs as text in subset fonts, which viewers +//! select, search and copy, shapes and ink as vector paths, pictures and icons as images. + +use super::{ + GlyphRun, Layer, PathStyle, Primitive, RasterImage, RenderError, Stroke, icon, srgb_byte, +}; +use parley::fontique::Blob; +use pdf_writer::{ + Content, Filter, Finish, Name, Pdf, Rect, Ref, Str, TextStr, + types::{ + BlendMode, CidFontType, FontFlags, LineCapStyle, LineJoinStyle, SystemInfo, + TextRenderingMode, UnicodeCmap, + }, +}; +use std::collections::{BTreeMap, HashMap, btree_map::Entry}; +use swash::{ + FontRef, StringId, + scale::{Render, ScaleContext, Source, StrikeWith, image::Content as Pixels}, + tag_from_bytes, + zeno::{Command, PathData}, +}; + +/// One sheet of paper. +pub struct Sheet<'a> { + /// Width and height in points. + pub size: [f32; 2], + /// Layers whose device units are points from the sheet's top left. + pub layers: Vec>, +} + +/// `sheets` as a PDF document titled `title`. +pub fn pdf(title: &str, sheets: &[Sheet<'_>]) -> Result, RenderError> { + let mut document = Document { + pdf: Pdf::new(), + next: 1, + fonts: Vec::new(), + images: HashMap::new(), + states: HashMap::new(), + scale: ScaleContext::new(), + rows: None, + }; + let catalog = document.reserve(); + let tree = document.reserve(); + let pages: Vec<_> = sheets + .iter() + .map(|sheet| { + let page = document.reserve(); + let content = document.reserve(); + let used = document.sheet(sheet, content)?; + Ok((page, used)) + }) + .collect::>()?; + for ((page, used), sheet) in pages.iter().zip(sheets) { + let mut writer = document.pdf.page(*page); + writer + .parent(tree) + .media_box(Rect::new(0.0, 0.0, sheet.size[0], sheet.size[1])) + .contents(used.content); + let mut resources = writer.resources(); + let mut fonts = resources.fonts(); + for font in &used.fonts { + let reference = document.fonts[*font].reference; + fonts.pair(Name(format!("F{font}").as_bytes()), reference); + } + fonts.finish(); + let mut images = resources.x_objects(); + for image in &used.images { + images.pair(Name(format!("I{}", image.get()).as_bytes()), *image); + } + images.finish(); + let mut states = resources.ext_g_states(); + for state in &used.states { + states.pair(Name(format!("G{}", state.get()).as_bytes()), *state); + } + } + document + .pdf + .pages(tree) + .kids(pages.iter().map(|(page, _)| *page)) + .count(pages.len() as i32); + document.pdf.catalog(catalog).pages(tree); + let info = document.reserve(); + document + .pdf + .document_info(info) + .title(TextStr(title)) + .producer(TextStr("Snowbound")); + let fonts = std::mem::take(&mut document.fonts); + for font in fonts.into_iter().filter(|font| font.outlined) { + document.write_font(font)?; + } + Ok(document.pdf.finish()) +} + +struct Document { + pdf: Pdf, + next: i32, + fonts: Vec, + /// Image XObjects by what they show. + images: HashMap, + /// Graphics states by fill and stroke opacity bits and whether they multiply. + states: HashMap<(u32, bool), Ref>, + scale: ScaleContext, + /// The top and bottom of the layer drawn, in its units, where it clips; lines of text + /// outside it are left out, so that no sheet's text layer holds text it does not show. + rows: Option<[f32; 2]>, +} + +#[derive(Hash, PartialEq, Eq)] +enum ImageKey { + Raster(u64), + Icon { + sources: usize, + size: u32, + tint: [u32; 3], + palette: [Option<[u32; 3]>; 3], + }, + Glyph { + font: u64, + index: u32, + glyph: u32, + size: u32, + color: [u32; 3], + }, +} + +/// A face the document shows glyphs of. +struct Font { + reference: Ref, + data: Blob, + index: u32, + /// Whether its glyphs are outlines the PDF embeds; others draw as pictures. + outlined: bool, + glyphs: subsetter::GlyphRemapper, + /// The text each subset glyph shows where it first appeared. + text: BTreeMap, +} + +/// What a sheet's content refers to. +struct Used { + content: Ref, + fonts: Vec, + images: Vec, + states: Vec, +} + +impl Used { + fn add(list: &mut Vec, item: T) { + if !list.contains(&item) { + list.push(item); + } + } +} + +fn compress(data: &[u8]) -> Vec { + miniz_oxide::deflate::compress_to_vec_zlib(data, 6) +} + +/// sRGB components of a linear colour. +fn encoded(color: [f32; 4]) -> [f32; 3] { + [color[0], color[1], color[2]].map(|value| f32::from(srgb_byte(value.clamp(0.0, 1.0))) / 255.0) +} + +/// Bézier handle length for a quarter circle of radius one. +const KAPPA: f32 = 0.552_284_8; + +/// Appends an ellipse's quarter arcs around `rect`'s corners of radii `radius`, as a +/// closed path. +fn rounded(content: &mut Content, [left, top, right, bottom]: [f32; 4], radius: [f32; 2]) { + let rx = radius[0].clamp(0.0, (right - left) / 2.0); + let ry = radius[1].clamp(0.0, (bottom - top) / 2.0); + if rx <= 0.0 || ry <= 0.0 { + content.rect(left, top, right - left, bottom - top); + return; + } + let [kx, ky] = [rx * KAPPA, ry * KAPPA]; + content.move_to(left + rx, top); + content.line_to(right - rx, top); + content.cubic_to(right - rx + kx, top, right, top + ry - ky, right, top + ry); + content.line_to(right, bottom - ry); + content.cubic_to( + right, + bottom - ry + ky, + right - rx + kx, + bottom, + right - rx, + bottom, + ); + content.line_to(left + rx, bottom); + content.cubic_to( + left + rx - kx, + bottom, + left, + bottom - ry + ky, + left, + bottom - ry, + ); + content.line_to(left, top + ry); + content.cubic_to(left, top + ry - ky, left + rx - kx, top, left + rx, top); + content.close_path(); +} + +fn circle(content: &mut Content, [x, y]: [f32; 2], radius: f32) { + rounded( + content, + [x - radius, y - radius, x + radius, y + radius], + [radius; 2], + ); +} + +/// The text each of `count` glyphs shows: a cluster's text goes to its first glyph, and a +/// ligature's later clusters to the glyph before them. +fn glyph_text( + text: &str, + clusters: &mut dyn Iterator, usize)>, + count: usize, +) -> Vec { + let mut texts = vec![String::new(); count]; + let mut at = 0_usize; + for (range, glyphs) in clusters { + let shown = text.get(range).unwrap_or_default(); + if glyphs == 0 { + if let Some(previous) = at.checked_sub(1).and_then(|at| texts.get_mut(at)) { + previous.push_str(shown); + } + continue; + } + if let Some(first) = texts.get_mut(at) { + first.push_str(shown); + } + at += glyphs; + } + texts +} + +impl Document { + fn reserve(&mut self) -> Ref { + let reference = Ref::new(self.next); + self.next += 1; + reference + } + + fn sheet(&mut self, sheet: &Sheet<'_>, content_ref: Ref) -> Result { + let mut used = Used { + content: content_ref, + fonts: Vec::new(), + images: Vec::new(), + states: Vec::new(), + }; + let mut content = Content::new(); + // Layers measure down from the top left, as the renderer's do. + content.transform([1.0, 0.0, 0.0, -1.0, 0.0, sheet.size[1]]); + for layer in &sheet.layers { + content.save_state(); + if let Some([left, top, right, bottom]) = layer.clip { + content + .rect(left, top, right - left, bottom - top) + .clip_nonzero() + .end_path(); + } + self.rows = layer + .clip + .map(|clip| [clip[1], clip[3]].map(|y| (y - layer.origin[1]) / layer.scale)); + content.transform([ + layer.scale, + 0.0, + 0.0, + layer.scale, + layer.origin[0], + layer.origin[1], + ]); + for primitive in layer.primitives { + self.primitive(&mut content, &mut used, primitive)?; + } + content.restore_state(); + } + let data = compress(&content.finish()); + self.pdf + .stream(content_ref, &data) + .filter(Filter::FlateDecode); + Ok(used) + } + + /// Sets the fill, or with `stroke` the stroke, to `color` with its opacity. + fn paint(&mut self, content: &mut Content, used: &mut Used, color: [f32; 4], stroke: bool) { + let [red, green, blue] = encoded(color); + if stroke { + content.set_stroke_rgb(red, green, blue); + } else { + content.set_fill_rgb(red, green, blue); + } + if color[3] < 1.0 { + let state = self.state(color[3], false); + Used::add(&mut used.states, state); + content.set_parameters(Name(format!("G{}", state.get()).as_bytes())); + } + } + + fn state(&mut self, opacity: f32, multiply: bool) -> Ref { + let key = (opacity.clamp(0.0, 1.0).to_bits(), multiply); + if let Some(state) = self.states.get(&key) { + return *state; + } + let state = self.reserve(); + let mut writer = self.pdf.ext_graphics(state); + writer + .non_stroking_alpha(opacity.clamp(0.0, 1.0)) + .stroking_alpha(opacity.clamp(0.0, 1.0)); + if multiply { + writer.blend_mode(BlendMode::Multiply); + } + writer.finish(); + self.states.insert(key, state); + state + } + + fn primitive( + &mut self, + content: &mut Content, + used: &mut Used, + primitive: &Primitive<'_>, + ) -> Result<(), RenderError> { + match primitive { + Primitive::Text { + text, + origin, + clip, + ink, + } => { + content.save_state(); + if let Some([left, top, right, bottom]) = *clip { + content + .rect(left, top, right - left, bottom - top) + .clip_nonzero() + .end_path(); + } + text.runs(&mut |run| self.run(content, used, run, *origin, *ink))?; + content.restore_state(); + } + Primitive::Icon { + sources, + origin, + size, + tint, + palette, + } => { + // Icons are small art; eight pixels a point keeps them sharp on paper. + let side = (size * 8.0).ceil().clamp(16.0, 512.0) as u32; + let key = ImageKey::Icon { + sources: sources.as_ptr() as usize, + size: side, + tint: [tint[0], tint[1], tint[2]].map(f32::to_bits), + palette: palette.bits(), + }; + let image = match self.images.get(&key) { + Some(image) => *image, + None => { + let raster = + icon::rasterize(sources, side, [tint[0], tint[1], tint[2]], palette); + let image = self.image([side; 2], &raster.data, false); + self.images.insert(key, image); + image + } + }; + content.save_state(); + if tint[3] < 1.0 { + let state = self.state(tint[3], false); + Used::add(&mut used.states, state); + content.set_parameters(Name(format!("G{}", state.get()).as_bytes())); + } + self.place( + content, + used, + image, + [origin[0], origin[1], origin[0] + size, origin[1] + size], + ); + content.restore_state(); + } + Primitive::Path { + data, + origin, + style, + colors, + } => { + let fill = matches!(style, PathStyle::Fill); + let (PathStyle::Fill | PathStyle::Stroke(_)) = style else { + return Ok(()); + }; + content.save_state(); + content.transform([1.0, 0.0, 0.0, 1.0, origin[0], origin[1]]); + let average = std::array::from_fn(|at| (colors[0][at] + colors[1][at]) / 2.0); + self.paint(content, used, average, !fill); + let mut last = [0.0_f32; 2]; + for command in data.commands() { + match command { + Command::MoveTo(to) => { + content.move_to(to.x, to.y); + last = [to.x, to.y]; + } + Command::LineTo(to) => { + content.line_to(to.x, to.y); + last = [to.x, to.y]; + } + Command::CurveTo(one, two, to) => { + content.cubic_to(one.x, one.y, two.x, two.y, to.x, to.y); + last = [to.x, to.y]; + } + Command::QuadTo(control, to) => { + let near = + |from: f32, control: f32| from + (control - from) * 2.0 / 3.0; + content.cubic_to( + near(last[0], control.x), + near(last[1], control.y), + near(to.x, control.x), + near(to.y, control.y), + to.x, + to.y, + ); + last = [to.x, to.y]; + } + Command::Close => { + content.close_path(); + } + } + } + match style { + PathStyle::Stroke(width) => { + content + .set_line_width(*width) + .set_line_cap(LineCapStyle::RoundCap) + .set_line_join(LineJoinStyle::RoundJoin) + .stroke(); + } + _ => { + content.fill_nonzero(); + } + } + content.restore_state(); + } + Primitive::Rect { rect, color } => { + content.save_state(); + self.paint(content, used, *color, false); + content + .rect(rect[0], rect[1], rect[2] - rect[0], rect[3] - rect[1]) + .fill_nonzero(); + content.restore_state(); + } + Primitive::RoundedRect { + rect, + radius, + stroke, + color, + } => { + content.save_state(); + self.paint(content, used, *color, stroke.is_some()); + rounded(content, *rect, *radius); + match stroke { + None => { + content.fill_nonzero(); + } + Some(Stroke::Solid(width)) => { + content.set_line_width(*width).stroke(); + } + Some(Stroke::Dashed(width)) => { + content + .set_line_width(*width) + .set_dash_pattern([width * 2.0, width * 2.0], 0.0) + .stroke(); + } + } + content.restore_state(); + } + Primitive::Gradient { + rect, + radius, + colors, + } => { + content.save_state(); + let average = std::array::from_fn(|at| (colors[0][at] + colors[1][at]) / 2.0); + self.paint(content, used, average, false); + rounded(content, *rect, *radius); + content.fill_nonzero(); + content.restore_state(); + } + // Soft shadows are for the screen. + Primitive::Shadow { .. } => {} + Primitive::Image { image, rect } => { + let key = ImageKey::Raster(image.id()); + let reference = match self.images.get(&key) { + Some(reference) => *reference, + None => { + let reference = self.raster(image); + self.images.insert(key, reference); + reference + } + }; + self.place(content, used, reference, *rect); + } + Primitive::Segment { + from, + to, + width, + round, + color, + } => { + content.save_state(); + self.paint(content, used, *color, true); + content + .set_line_width(*width) + .set_line_cap(if *round { + LineCapStyle::RoundCap + } else { + LineCapStyle::ProjectingSquareCap + }) + .move_to(from[0], from[1]) + .line_to(to[0], to[1]) + .stroke(); + content.restore_state(); + } + Primitive::Taper { + from, + to, + widths, + color, + } => { + content.save_state(); + self.paint(content, used, *color, false); + let [from_radius, to_radius] = widths.map(|width| width / 2.0); + // Each part fills on its own, as their windings differ. + circle(content, *from, from_radius); + content.fill_nonzero(); + circle(content, *to, to_radius); + content.fill_nonzero(); + let [dx, dy] = [to[0] - from[0], to[1] - from[1]]; + let length = dx.hypot(dy); + if length > (from_radius - to_radius).abs() { + // The lines touching both ends' circles. + let [ux, uy] = [dx / length, dy / length]; + let sine = (from_radius - to_radius) / length; + let cosine = (1.0 - sine * sine).sqrt(); + let touch = |center: &[f32; 2], radius: f32, side: f32| { + [ + center[0] + radius * (-uy * side * cosine + ux * sine), + center[1] + radius * (ux * side * cosine + uy * sine), + ] + }; + let corners = [ + touch(from, from_radius, 1.0), + touch(to, to_radius, 1.0), + touch(to, to_radius, -1.0), + touch(from, from_radius, -1.0), + ]; + content.move_to(corners[0][0], corners[0][1]); + for corner in &corners[1..] { + content.line_to(corner[0], corner[1]); + } + content.close_path().fill_nonzero(); + } + content.restore_state(); + } + Primitive::Highlight { + from, + to, + width, + color, + } => { + content.save_state(); + let state = self.state(color[3], true); + Used::add(&mut used.states, state); + content.set_parameters(Name(format!("G{}", state.get()).as_bytes())); + let [red, green, blue] = encoded(*color); + content + .set_stroke_rgb(red, green, blue) + .set_line_width(*width) + .set_line_cap(LineCapStyle::ProjectingSquareCap) + .move_to(from[0], from[1]) + .line_to(to[0], to[1]) + .stroke(); + content.restore_state(); + } + } + Ok(()) + } + + /// Draws image XObject `image` filling `rect`. + fn place(&mut self, content: &mut Content, used: &mut Used, image: Ref, rect: [f32; 4]) { + Used::add(&mut used.images, image); + content.save_state(); + // Image space runs up from the bottom left. + content.transform([ + rect[2] - rect[0], + 0.0, + 0.0, + rect[1] - rect[3], + rect[0], + rect[3], + ]); + content.x_object(Name(format!("I{}", image.get()).as_bytes())); + content.restore_state(); + } + + /// A picture as an image XObject: opaque photographs as JPEG, others losslessly. + fn raster(&mut self, image: &RasterImage) -> Ref { + // Pixels are premultiplied in linear light. + let straight: Vec = image + .pixels() + .chunks_exact(4) + .flat_map(|pixel| { + let alpha = pixel[3]; + if alpha == 255 || alpha == 0 { + return [pixel[0], pixel[1], pixel[2], alpha]; + } + let [red, green, blue] = [pixel[0], pixel[1], pixel[2]].map(|byte| { + let linear = super::linear(f32::from(byte) / 255.0); + srgb_byte((linear * 255.0 / f32::from(alpha)).min(1.0)) + }); + [red, green, blue, alpha] + }) + .collect(); + let size = image.size(); + let opaque = straight.chunks_exact(4).all(|pixel| pixel[3] == 255); + if opaque && size[0] * size[1] >= 64 * 64 { + let rgb: Vec = straight + .chunks_exact(4) + .flat_map(|pixel| [pixel[0], pixel[1], pixel[2]]) + .collect(); + let mut jpeg = Vec::new(); + let encoder = image::codecs::jpeg::JpegEncoder::new_with_quality(&mut jpeg, 92); + if image::ImageEncoder::write_image( + encoder, + &rgb, + size[0], + size[1], + image::ExtendedColorType::Rgb8, + ) + .is_ok() + { + let reference = self.reserve(); + let mut writer = self.pdf.image_xobject(reference, &jpeg); + writer.filter(Filter::DctDecode); + writer + .width(size[0] as i32) + .height(size[1] as i32) + .color_space_name(Name(b"DeviceRGB")) + .bits_per_component(8) + .interpolate(true); + return reference; + } + } + self.image(size, &straight, true) + } + + /// Straight sRGB RGBA pixels as a losslessly compressed image XObject. + fn image(&mut self, [width, height]: [u32; 2], rgba: &[u8], interpolate: bool) -> Ref { + let rgb: Vec = rgba + .chunks_exact(4) + .flat_map(|pixel| [pixel[0], pixel[1], pixel[2]]) + .collect(); + let mask = rgba.chunks_exact(4).any(|pixel| pixel[3] != 255).then(|| { + let alpha: Vec = rgba.chunks_exact(4).map(|pixel| pixel[3]).collect(); + let mask = self.reserve(); + let data = compress(&alpha); + let mut writer = self.pdf.image_xobject(mask, &data); + writer.filter(Filter::FlateDecode); + writer + .width(width as i32) + .height(height as i32) + .color_space_name(Name(b"DeviceGray")) + .bits_per_component(8) + .interpolate(interpolate); + mask + }); + let reference = self.reserve(); + let data = compress(&rgb); + let mut writer = self.pdf.image_xobject(reference, &data); + writer.filter(Filter::FlateDecode); + writer + .width(width as i32) + .height(height as i32) + .color_space_name(Name(b"DeviceRGB")) + .bits_per_component(8) + .interpolate(interpolate); + if let Some(mask) = mask { + writer.s_mask(mask); + } + reference + } + + /// The document's face for a run's font, added on first use. + fn font(&mut self, data: &Blob, index: u32) -> Result { + if let Some(found) = self + .fonts + .iter() + .position(|font| font.data.id() == data.id() && font.index == index) + { + return Ok(found); + } + let face = FontRef::from_index(data.as_ref(), index as usize) + .ok_or(RenderError::UnreadableFont)?; + let outlined = face.table(tag_from_bytes(b"glyf")).is_some() + || face.table(tag_from_bytes(b"CFF ")).is_some(); + let reference = self.reserve(); + self.fonts.push(Font { + reference, + data: data.clone(), + index, + outlined, + glyphs: subsetter::GlyphRemapper::new(), + text: BTreeMap::new(), + }); + Ok(self.fonts.len() - 1) + } + + fn run( + &mut self, + content: &mut Content, + used: &mut Used, + run: GlyphRun<'_>, + origin: [f32; 2], + ink: [f32; 4], + ) -> Result<(), RenderError> { + let [top, bottom] = [ + origin[1] + run.line[0], + origin[1] + run.line[0] + run.line[1], + ]; + if self + .rows + .is_some_and(|[first, last]| bottom <= first || top >= last) + { + return Ok(()); + } + let font = self.font(run.font, run.index)?; + let color = run.color.unwrap_or(ink); + let glyphs: Vec<_> = run.glyphs.collect(); + let texts = glyph_text(run.text, run.clusters, glyphs.len()); + content.save_state(); + if self.fonts[font].outlined { + Used::add(&mut used.fonts, font); + self.paint(content, used, color, false); + let face = FontRef::from_index(run.font.as_ref(), run.index as usize) + .ok_or(RenderError::UnreadableFont)?; + let units = f32::from(face.metrics(&[]).units_per_em.max(1)); + let advances = face.glyph_metrics(&[]); + let name = format!("F{font}"); + content + .begin_text() + .set_font(Name(name.as_bytes()), run.size); + if run.embolden { + self.paint(content, used, color, true); + content + .set_text_rendering_mode(TextRenderingMode::FillStroke) + .set_line_width(run.size / 24.0); + } + let shear = run.skew.map_or(0.0, |degrees| degrees.to_radians().tan()); + let mut shown: Vec<(u16, f32)> = Vec::new(); + let mut pen: Option<[f32; 2]> = None; + let flush = |content: &mut Content, shown: &mut Vec<(u16, f32)>| { + if shown.is_empty() { + return; + } + let mut positioned = content.show_positioned(); + let mut items = positioned.items(); + for (glyph, adjust) in shown.drain(..) { + if adjust != 0.0 { + items.adjust(adjust); + } + items.show(Str(&glyph.to_be_bytes())); + } + }; + for (glyph, text) in glyphs.iter().zip(texts) { + let Ok(id) = u16::try_from(glyph.id) else { + continue; + }; + let face = &mut self.fonts[font]; + let cid = face.glyphs.remap(id); + let [x, y] = [origin[0] + glyph.x, origin[1] + glyph.y]; + let conflict = !text.is_empty() + && match face.text.entry(cid) { + Entry::Vacant(entry) => { + entry.insert(text.clone()); + false + } + Entry::Occupied(entry) => *entry.get() != text, + }; + let advance = advances.advance_width(id) / units * run.size; + match pen { + Some([at, line]) if !conflict && (line - y).abs() < 0.001 => { + shown.push((cid, (at - x) * 1000.0 / run.size)); + } + _ => { + flush(content, &mut shown); + content.set_text_matrix([1.0, 0.0, shear, -1.0, x, y]); + if conflict { + // A glyph shared by different text says what it shows here. + content + .begin_marked_content_with_properties(Name(b"Span")) + .properties() + .actual_text(TextStr(&text)); + content.show(Str(&cid.to_be_bytes())); + content.end_marked_content(); + pen = None; + continue; + } + shown.push((cid, 0.0)); + } + } + pen = Some([x + advance, y]); + } + flush(content, &mut shown); + content.end_text(); + } else { + for glyph in &glyphs { + self.glyph_picture(content, used, &run, *glyph, origin, color); + } + } + for decoration in run.decorations { + self.paint(content, used, decoration.color.unwrap_or(color), false); + content + .rect( + origin[0] + decoration.x, + origin[1] + decoration.y, + decoration.width, + decoration.thickness, + ) + .fill_nonzero(); + } + content.restore_state(); + Ok(()) + } + + /// A glyph of a face without outlines the PDF can embed, such as a colour emoji, drawn + /// as a picture four pixels a point. + fn glyph_picture( + &mut self, + content: &mut Content, + used: &mut Used, + run: &GlyphRun<'_>, + glyph: super::Glyph, + origin: [f32; 2], + color: [f32; 4], + ) { + const DENSITY: f32 = 4.0; + let Ok(id) = u16::try_from(glyph.id) else { + return; + }; + let Some(face) = FontRef::from_index(run.font.as_ref(), run.index as usize) else { + return; + }; + let size = run.size * DENSITY; + let mut scaler = self + .scale + .builder(face) + .size(size) + .normalized_coords(run.coords.iter().copied()) + .build(); + let Some(rendered) = Render::new(&[ + Source::ColorOutline(0), + Source::ColorBitmap(StrikeWith::BestFit), + Source::Outline, + ]) + .render(&mut scaler, id) else { + return; + }; + let placement = rendered.placement; + if placement.width == 0 || placement.height == 0 { + return; + } + let key = ImageKey::Glyph { + font: run.font.id(), + index: run.index, + glyph: glyph.id, + size: size.to_bits(), + color: [color[0], color[1], color[2]].map(f32::to_bits), + }; + let image = match self.images.get(&key) { + Some(image) => *image, + None => { + let [red, green, blue] = encoded(color).map(|value| (value * 255.0).round() as u8); + let rgba: Vec = match rendered.content { + Pixels::Mask => rendered + .data + .iter() + .flat_map(|coverage| [red, green, blue, *coverage]) + .collect(), + Pixels::Color | Pixels::SubpixelMask => rendered.data.clone(), + }; + let image = self.image([placement.width, placement.height], &rgba, true); + self.images.insert(key, image); + image + } + }; + let [x, y] = [ + origin[0] + glyph.x + placement.left as f32 / DENSITY, + origin[1] + glyph.y - placement.top as f32 / DENSITY, + ]; + self.place( + content, + used, + image, + [ + x, + y, + x + placement.width as f32 / DENSITY, + y + placement.height as f32 / DENSITY, + ], + ); + } + + /// Embeds `font`'s subset as a CID-keyed Type 0 font with a ToUnicode map. + fn write_font(&mut self, font: Font) -> Result<(), RenderError> { + let data = font.data.as_ref(); + let face = + FontRef::from_index(data, font.index as usize).ok_or(RenderError::UnreadableFont)?; + let subset = subsetter::subset(data, font.index, &font.glyphs) + .map_err(|_| RenderError::UnreadableFont)?; + let cff = face.table(tag_from_bytes(b"CFF ")).is_some(); + let metrics = face.metrics(&[]); + let scale = 1000.0 / f32::from(metrics.units_per_em.max(1)); + let advances = face.glyph_metrics(&[]); + let widths: Vec = font + .glyphs + .remapped_gids() + .map(|old| advances.advance_width(old) * scale) + .collect(); + let postscript: String = face + .localized_strings() + .find_by_id(StringId::PostScript, None) + .map(|name| name.chars().filter(char::is_ascii_alphanumeric).collect()) + .filter(|name: &String| !name.is_empty()) + .unwrap_or_else(|| "Font".to_owned()); + // A subset's name starts with six capitals naming the subset. + let mut hash = font.reference.get() as u32; + let tag: String = (0..6) + .map(|_| { + hash = hash.wrapping_mul(1_103_515_245).wrapping_add(12_345); + char::from(b'A' + (hash >> 16) as u8 % 26) + }) + .collect(); + let base = format!("{tag}+{postscript}"); + let [cid, descriptor, file, map] = [(); 4].map(|_| self.reserve()); + let info = SystemInfo { + registry: Str(b"Adobe"), + ordering: Str(b"Identity"), + supplement: 0, + }; + self.pdf + .type0_font(font.reference) + .base_font(Name(base.as_bytes())) + .encoding_predefined(Name(b"Identity-H")) + .descendant_font(cid) + .to_unicode(map); + let mut writer = self.pdf.cid_font(cid); + writer + .subtype(if cff { + CidFontType::Type0 + } else { + CidFontType::Type2 + }) + .base_font(Name(base.as_bytes())) + .system_info(info) + .font_descriptor(descriptor) + .default_width(0.0); + if !cff { + writer.cid_to_gid_map_predefined(Name(b"Identity")); + } + writer.widths().consecutive(0, widths); + writer.finish(); + let mut writer = self.pdf.font_descriptor(descriptor); + writer + .name(Name(base.as_bytes())) + .flags(FontFlags::SYMBOLIC) + .bbox(Rect::new( + 0.0, + -metrics.descent * scale, + metrics.max_width * scale, + metrics.ascent * scale, + )) + .italic_angle(0.0) + .ascent(metrics.ascent * scale) + .descent(-metrics.descent * scale) + .cap_height(metrics.cap_height * scale) + .stem_v(80.0); + if cff { + writer.font_file3(file); + } else { + writer.font_file2(file); + } + writer.finish(); + let compressed = compress(&subset); + let mut stream = self.pdf.stream(file, &compressed); + stream.filter(Filter::FlateDecode); + if cff { + stream.pair(Name(b"Subtype"), Name(b"OpenType")); + } + stream.finish(); + let mut cmap = UnicodeCmap::new(Name(b"Custom"), info); + for (glyph, text) in &font.text { + cmap.pair_with_multiple(*glyph, text.chars()); + } + let cmap = compress(&cmap.finish()); + self.pdf.stream(map, &cmap).filter(Filter::FlateDecode); + Ok(()) + } +} diff --git a/crates/draw/src/render/text.rs b/crates/draw/src/render/text.rs index 04841e9e772c8ad3b960e41a8e9c5c9980785b78..b748bf3615966ef00c0a8dedeb41d4202ddee9a7 100644 --- a/crates/draw/src/render/text.rs +++ b/crates/draw/src/render/text.rs @@ -1,5 +1,6 @@ use crate::RenderError; use parley::fontique::Blob; +use std::ops::Range; /// Text the renderer can paint, as glyph runs in layer units. Owners recover their /// concrete text from a primitive through `Any`. @@ -32,6 +33,11 @@ pub struct GlyphRun<'a> { pub glyphs: &'a mut dyn Iterator, /// Underline and strikethrough, painted after the glyphs. pub decorations: &'a [Decoration], + /// The source the glyphs show, for a document's text layer; the renderer ignores it. + pub text: &'a str, + /// Each cluster's bytes of `text` and how many glyphs show it, in `glyphs`' order; a + /// ligature's later clusters take none. + pub clusters: &'a mut dyn Iterator, usize)>, } /// A glyph's baseline position. @@ -53,10 +59,12 @@ pub struct Decoration { pub color: Option<[f32; 4]>, } -/// Paints one parley glyph run with its line's baseline moved to `baseline`, its glyphs -/// raised by `rise` and `backdrop` behind them. +/// Paints one parley glyph run of `text` laid out, with its line's baseline moved to +/// `baseline`, its glyphs raised by `rise` and `backdrop` behind them. +#[allow(clippy::too_many_arguments)] pub fn paint_parley_run( run: &parley::GlyphRun<'_, B>, + text: &str, baseline: f32, rise: f32, line: [f32; 2], @@ -104,6 +112,17 @@ pub fn paint_parley_run( x: glyph.x, y: glyph.y + baseline - line_baseline - rise, }); + // The run's clusters are those of its style within its span of the line; walked only + // when a text layer asks. + let [start, end] = [run.offset(), run.offset() + run.advance()]; + let mut at = None; + let mut clusters = run.run().visual_clusters().filter_map(|cluster| { + let x = *at.get_or_insert_with(|| cluster.visual_offset().unwrap_or(start)); + at = Some(x + cluster.advance()); + let within = x > start - 0.01 && x < end - 0.01; + (cluster.style_index() == run.style_index() && within) + .then(|| (cluster.text_range(), cluster.glyphs().count())) + }); paint(GlyphRun { font: &font.data, index: font.index, @@ -116,5 +135,7 @@ pub fn paint_parley_run( line, glyphs: &mut glyphs, decorations: &decorations, + text, + clusters: &mut clusters, }) } diff --git a/crates/mobile/src/lib.rs b/crates/mobile/src/lib.rs index bb7e47b4efd3594c9d93a7759dddc1f7bfe37c84..12a8df2fe9d1e251168758451c7d622345ededca 100644 --- a/crates/mobile/src/lib.rs +++ b/crates/mobile/src/lib.rs @@ -29,7 +29,7 @@ use draw::edit::{Key, NamedKey, SelectionUnit}; use onestore::{ ExGuid, op::{Edit, Op, PageOp}, - page::{Image, Page, ink::ShapeKind}, + page::{Page, ink::ShapeKind}, }; use parley::{Affinity, BoundingBox}; use std::{ @@ -503,25 +503,9 @@ impl Canvas { Ok(moved(self.page.set_paper(color, rules, Some(art))?)) } - /// Puts a picture of `size` points after the caret's paragraph. + /// Puts a picture of `size` points at the caret. fn insert_picture(&mut self, bytes: &[u8], size: [f32; 2]) -> Result { - let image = Image { - id: onestore::page::text::new_id()?, - layout: onestore::document::Layout { - max_width: Some(size[0]), - max_height: Some(size[1]), - ..Default::default() - }, - size: Some(size), - bytes: Some(bytes.into()), - display: None, - alt: None, - background: false, - printout: None, - }; - let page = &mut self.page; - page.editor.insert_picture(&mut page.engine, image)?; - Ok(true) + Ok(moved(self.page.insert_picture(bytes.to_vec(), size)?)) } /// Gives the page date `seconds` since 1970 (keeping the stored fraction of a second), @@ -1257,8 +1241,8 @@ pub extern "C" fn sb_view_page_text(view: &View) -> *mut c_char { owned(view.canvas.page_text()) } -/// Puts the picture file `bytes` (JPEG or PNG), `width` × `height` points, after the -/// caret's paragraph. +/// Puts the picture file `bytes` (JPEG or PNG), `width` × `height` points, at the caret: +/// splitting its paragraph, or on the page at a caret on blank page. /// /// # Safety /// `bytes` holds `length` bytes. diff --git a/crates/mobile/src/tests.rs b/crates/mobile/src/tests.rs index 8a0acf7c282f2e2158de67ee10c8498a633a4e66..c1c4f60b0e29b04e67442bc69e4eb4d43cddc4f8 100644 --- a/crates/mobile/src/tests.rs +++ b/crates/mobile/src/tests.rs @@ -430,7 +430,7 @@ fn find_selects_the_match_and_formatting_reports_and_toggles() { } #[test] -fn a_picture_goes_after_the_caret_paragraph_and_undoes() { +fn a_picture_goes_in_at_the_caret_and_undoes() { let (_directory, section) = features(); let mut canvas = canvas(§ion, "Paragraph controls"); focus(&mut canvas, "Collapsed parent"); diff --git a/crates/notebook/Cargo.toml b/crates/notebook/Cargo.toml index 9258c4f86855d4698660c154e6e8d3fff601ca21..851557dd3182bb5006faec812b122ceb012b636e 100644 --- a/crates/notebook/Cargo.toml +++ b/crates/notebook/Cargo.toml @@ -23,6 +23,9 @@ zeroize = { version = "1.9.0", optional = true } [target.'cfg(target_vendor = "apple")'.dependencies] nix = { version = "0.31", default-features = false, features = ["fs"] } +[target.'cfg(windows)'.dependencies] +windows-sys = { version = "0.61", features = ["Win32_Storage_FileSystem"] } + [dev-dependencies] libc = "0.2" serde_json = "1" diff --git a/crates/notebook/src/lib.rs b/crates/notebook/src/lib.rs index daea3066e210c21026b023c8002a90bfd20e2c21..d7db2dc031a1592a5751fe4055be3543fac0bc4f 100644 --- a/crates/notebook/src/lib.rs +++ b/crates/notebook/src/lib.rs @@ -1,4 +1,5 @@ -#![forbid(unsafe_code)] +// One Win32 call, where std has no safe form: `session`'s hidden attribute. +#![deny(unsafe_code)] #![doc = include_str!("../README.md")] pub mod discover; diff --git a/crates/notebook/src/session.rs b/crates/notebook/src/session.rs index c043efed2bc82cbbfd15cd6c8d836e38860e5b6b..309ddf3bafc58fc0833fed69a2392a31ac04eb1e 100644 --- a/crates/notebook/src/session.rs +++ b/crates/notebook/src/session.rs @@ -168,7 +168,9 @@ impl Storage for Directory { Ok(std::fs::create_dir(self.path(path))?) } - /// macOS keeps the attribute as `UF_HIDDEN`, and passes it on to a share it mounted. + /// macOS keeps the attribute as `UF_HIDDEN`, and passes it on to a share it mounted; + /// Linux has no attribute to set, a dot folder being hidden there already. + #[cfg_attr(windows, allow(unsafe_code))] fn hide(&self, path: &str) -> Result<()> { #[cfg(target_vendor = "apple")] { @@ -181,7 +183,29 @@ impl Storage for Directory { .map_err(io::Error::from)?; } } - #[cfg(not(target_vendor = "apple"))] + #[cfg(windows)] + { + use std::os::windows::ffi::OsStrExt; + use windows_sys::Win32::Storage::FileSystem::{ + FILE_ATTRIBUTE_HIDDEN, GetFileAttributesW, INVALID_FILE_ATTRIBUTES, + SetFileAttributesW, + }; + let path: Vec = self + .path(path) + .as_os_str() + .encode_wide() + .chain([0]) + .collect(); + // SAFETY: `path` is a NUL-terminated UTF-16 string that outlives both calls. + let attributes = unsafe { GetFileAttributesW(path.as_ptr()) }; + if attributes == INVALID_FILE_ATTRIBUTES + || unsafe { SetFileAttributesW(path.as_ptr(), attributes | FILE_ATTRIBUTE_HIDDEN) } + == 0 + { + return Err(io::Error::last_os_error().into()); + } + } + #[cfg(not(any(target_vendor = "apple", windows)))] let _ = path; Ok(()) } diff --git a/crates/onestore/examples/opts29_dump.rs b/crates/onestore/examples/opts29_dump.rs new file mode 100644 index 0000000000000000000000000000000000000000..9fd4bf57f6bce83ca59d4fb7f4742eb7e855f30f --- /dev/null +++ b/crates/onestore/examples/opts29_dump.rs @@ -0,0 +1,29 @@ +use onestore::{ObjectData, PropertySets, RevisionIndex, Store, Value}; +use std::{env, fs}; + +fn main() -> Result<(), Box> { + for path in env::args_os().skip(1) { + let bytes = fs::read(&path)?; + let store = Store::parse(&bytes)?; + let index = RevisionIndex::parse(&store)?; + println!("== {path:?}"); + for space in index.spaces.keys() { + let Ok(resolved) = index.resolve_active(*space) else { continue }; + println!("-- space {space:?}"); + for (id, object) in &resolved.objects { + let ObjectData::Properties(data) = object.data else { continue }; + let sets = PropertySets::parse(data)?; + println!("{id:?} jcid={:#x}", object.jcid); + for p in &sets.sets[0] { + let v = match &p.value { + Value::Bytes(b) if b.len() <= 64 => format!("{:02x?}", b), + Value::Bytes(b) => format!("{} bytes", b.len()), + other => format!("{other:?}").chars().take(120).collect(), + }; + println!(" {:#010x} {v}", p.id); + } + } + } + } + Ok(()) +} diff --git a/crates/snowbound/Cargo.toml b/crates/snowbound/Cargo.toml index 708a3a25438b6121fb13e2fdfbb0454afc67d278..a582ecf29cd0fbe27eff2fe1b7e75524912468bb 100644 --- a/crates/snowbound/Cargo.toml +++ b/crates/snowbound/Cargo.toml @@ -10,7 +10,7 @@ default = ["wgpu"] wgpu = ["draw/wgpu", "dep:wgpu"] [dependencies] -canvas = { path = "../canvas", features = ["interaction"] } +canvas = { path = "../canvas", features = ["interaction", "pdf"] } draw = { path = "../draw", default-features = false, features = ["render"] } ui = { path = "../ui" } png = "0.18" @@ -39,6 +39,10 @@ objc2-app-kit = { version = "0.2.2", default-features = false, features = ["NSAl objc2-foundation = { version = "0.2.2", default-features = false, features = ["NSString", "NSThread", "NSAttributedString", "NSDate", "NSCalendar", "NSDateFormatter", "NSGeometry", "NSLocale", "NSPathUtilities", "NSTimeZone", "NSURL", "NSArray", "NSRange", "NSError", "NSFileCoordinator", "NSFilePresenter", "NSFileVersion", "NSFileManager", "NSNotification", "NSOperation", "block2"] } block2 = "0.5.1" +[target.'cfg(not(target_os = "macos"))'.dependencies] +# Clipboard bitmaps; macOS reads the pasteboard's PNG and TIFF itself. +arboard = { version = "3.6.1", default-features = false, features = ["image-data"] } + [target.'cfg(windows)'.dependencies] windows-sys = { version = "0.61", features = [ "Win32_Foundation", diff --git a/crates/snowbound/assets/icon/Assets.car b/crates/snowbound/assets/icon/Assets.car new file mode 100644 index 0000000000000000000000000000000000000000..782e18079fb131583a46fa6eca0273a9af6b11a2 GIT binary patch literal 36936 zcmeHw1zc6ly7#8L1qp!-(%oH~4hiW}y1PR}I+R99MGz^Gl#Yhum(*UaqAFwYuERb>r#Cszv)2m}YHF$fgF0Ro{C zgFxY>0QLa%LjD&spbpWL>OcU2@J`!E09XlztBh*us&eWOWg#h`Z)hoi!2nj2kCq7A!{#*JJ{4@Pee3BkWejyhOTrhCKzy$*r3|ug9!N3Ir7Ytl5aKXR@ z0~ZWjFz}yb;M{r&(&;J+7U&p|v-03TSZ6`N!j{coi!QJ=7koeo0lfq$u!aF50+a+$ zU@a9y1}G_@K>Tfe0P$RPU~2`KfMNg&`xid2 z_u$9Y035(#19~AB3|ug9!N3Ir7Ytl5aKXR@0~ZWjFmS=Z1p^lhTrluIkO379h_kbW ziK~gDnT3jpgN3w-s~yC}1Mn$05ttvrdHFs4`LwWfFh7CwqHwN!O&dpd6H|Mb|HmH! zTVyydzn8D!#~4c!Pmzx&2IamVXDx5A$9)FTdx9VM}`xyYr1YpC9IJabAAQZ}h_-$c5{xm<#(*}_9`C;BB=jBiH!@P9>IiDZq z-Ev<3G(XIP2axmmVcsw2N8<>CA=_5Fw<&XM&1D*%W z+vdFdqw-E4$@wh5ln3+HIWK>wJlN$wy4hL#DuMdIypPVy-^s6ezJs675A#+!FYXSO zb}$SZ$H0Q&kIh4{IRNI*1vqR0cRX1fge?-Di53Xvhjik1q@bZG_4}N0mhQ}c2MYQ- z_59;G{4L(j^8XbUwyEi?o{m8HD^RENbJq%hVGEV;?oaYw|+~Uvp zRllbCqtC!NhAALW_r&%eyn;Y$r}iWQ_Ibj`iC^4b!pGkt{paoelFUXo7UqSPE<4lpMN7Y{Dd0yWsn#@yXnl$sc8*4o0x%Gw=_JtrpOYGLLM z25~P5@bOWDeMG6bfMPgN2{_m#LAk=XpQU|B2796xjXw z&pf}UKsuoHT&uRgCQ+;@bI=5~+NZhq#|K4VjvRmtaeHIXYiLLQvuEfL(DA_xloxnN zx|MNq;@wAzxue8%?G#w2WW#tf=zFPDYaWI-{P|RcB67DL!wMasa z^PFcs3zbyl%ZvkiR3x-;RHx;O$^QJhSN@%t3T8PE%REoy7oX~g$x726S19=NwHi^( z6!nVi#mR;a*I$Z<(o4%e>H4{Yq4FQDUea|ac91nxi!Nx!L^68Gq#5BLsk z>(aaLNtA~z=*9)&nlJV&Ym4cRg_I5nH#cd}4AV)46lcNBCHcr7RW@J)S# zR=#5{ReN+$;E!OL+ZQD-N~u4s_yOmET!wGLOZA25YoVMR*hUK8PQx9+Xf?AF_V)d) zCe@K|f}YXEd)NymmAP?rbk|@oebj-bE9zk!aTrt`d(Gj1W$g@>*A!ez4s;OWi{A); zsG#qscrwVBgy*&MEuB~7@~pN*H6px>e<<_%=K$nJCT9Vm$+AcJK%Y45~_2Wp06=BJh5P$6`bQnNyXGQ3!Y#~wO=-4Ld6(*JB)ZDE}DZGpE z4qZfi7J|c{kE30qU&N$p)*tl9Khh;MBG9ZEqDaJ*d-m7};`kmU1*B(_lHwx`cuYX{A8^6+$?39G&=|S+K zLE@IfI*W+KhC0qGT>{GXcV&nuG74)gm~zEg@RJI|5*1rBw%>9p(bXkf%B!io2~_)> zMfvWe_D35cUs@MNo0v?gBP%@$GY%bexf>q(1#Hc=$0WjLy!Xfi!#`+blj+;7qg$KL zWpwz%hYy;RQI&?`xpVq%WC?Ax^jl_fE|Aqkh+vz=dKAJTS>vb%Gg8pI<1$91CXBUa zy|tz26#E{IE!=RB0GCcCRDMh-keJWlI@MgTAozgTAJ#EU|{J0ho{hfx6Q!BssyfHkU8U;abvPYUn zW*5N&R7i%2%h#9VoY%_MeR@1*F+zLE5HMaP#b_gUUM@(y&-kp4%&Tv0*)rIyuwz(n zHJ_`Sekh2|`Sxz{u~t^d=IvJb1d?wZpJhX`1E)~gv2tT`rOb*&KI(Sp#YRL&RnejH z#s=IBb&vV5HPf@R9ZV?|&?Crkjf8(4zcbkRdN4YFDaZR*yrZ2`XeI$l_`@mY0*zGG z5){G*h`AN%X0i{s(sNp@r9?-y2~48yDLTB2ZFXZ_7Dsei{#3#EJO-MWK9Hffp|r@n z?YkdpGpk9}NTr$QvNlxSbTjPxW8J*3x>n6-8Of6ZNTbGXJp?9~j4~do`Yu^L6F{6t zCk0iHEAJfMnLMP2$LFE7nb_Rlpy$P@T?&s(`Tk7PMAc%>tKzb!sHe-A5?w4>sA@`o z7G(;OM|#5&bxQzz`(tq<{{v9->(~1SpE@VSk8bUK{fr~wfB1c=h0`m?B2WqrRT8>; zyv#o-erxX#fn!SWs@)KaV#|7Za@WzLt<}k65#OfC4<&aF5#k=-`M$Sx4BI(zCdRo) z0sY4&1ga*ORn5Xg2#TMOS|nn;#Z3dKGmeOBaUF$`F+G4T_Q#9?z3HM<9LNJ zjk{rRH+pIsOCorbqS4GD>FO6916#xq+grqNIu38CD>O&d5Z!Ib@F9v0M^{7e^t=$U zsq4rBMa{XcYGQx9f#_05ifLv^Cs`gRBMrV(zDg{SkcTF9=Sz_>G`b#**gbv@^UZ*E z>HIzN+-T!W$wweebG2`wRES@8jGbRU#6nADPo@uC{CHDALL{9O?Oit?6JB#ZDc;okA!!uC@~DwmEVs+Js^92ZkGT*h;}7k&(fTnjnz^va2(#&7 zaJFHzupPQUmLSSD18rI85`9CtihP%>Cpgi`1qg`Zy$y{VW%MHjBEyR!uEjnydCbQ$ zLHn`hV-LYL=GK>M5Q=%8a2uPA>~2>{qiTkcbm)9AS^9YU#LYG|V<)o+#Aw4Fjvyp46E#j-7u51#vEFaR zdeCEqS`!8l%IIN1YC%a4xOL=$c|TT)>0w7wySlJa6a&A=%!Mg~IQ|{5eu+ZojBI_kd!>@|>ijWDTIL04j zhFp<-8Nguw5&(weRc~vb zdvg?4=uS2fm3!KFI3NG4j)$?7k$RAolmXg?ow+dr@o_y8-_|rG17@wO8mkdeP5Qo+ z3aVXbL&;nKR@H$9=5UiK<$ zh0|Csx{Zn2Vzt4^K=-Pq4HUO4CW=h)X%qR)E4>bOzsQl^>c!~Df|i!WDy-HpE+V@yyqY(9u*~5?^ybP8_Mzh+hdHe*W*55O8AhC zb@}*5se3#;Ii}qWTqq0CrF2TqIjPG_ zNldRkGUdU}v`@Tj03sztU@cu0)Nc-oGB0ovH=^5M`g0=@ zMW!h&L^Kbomr}WyGAhcu-&DMGi72@V6e_1g_4-MG5xVO7(&bFKvCVsvcn*gNOA$V= zdwiw~jW}-R&nEA%J={gA#Atg(y#$FZ3E47UVjiRMUMHkOQ~a(j6Bup;W^i7(yeUAs zpCAyEr4y06zDfvXTD-k5*t|?A0(saVlN~y-v@U4iHMHhQ$cx8X{08!z#!%8Mz>J@4) zujMN#p4CHwxSm#hf|r)qx&=XtD~WFI>!?D7-?@`1Gco-68`u?}@?T=xP?&A^*z1eo zSifZ5u%r|y_}uA@^LCz~`&4nZpz-mF7`NJy3LkgG{x~bQ@$R^yrNj<-6l*AjrY;JX zlb^>Om%ZhekM!=qxobVDFEI1nb|)G3sdgrLy5VR~a(_K$6VnB(c|4rEa$`XUIkj$7 z8(Fii-yVT1aJc*U0i<59ptv!bO3^_vooL}LdeU7`0Y!zDoD+0;;nLXQCFLOXeqIV4 z>_j-`mA45H(iLo4smo|ksXoR-ougiQRsRBE9^8KSjn1r02wUC zSRbYJ0OVU5pWyt3Q5rKn>RgQjsveQ*>SV=Z@?Fw?Q@MeHDO9-xkE}Z~4u_1sYz_*Z z|GM%XWM*IZ9>mD^!YUJ7)y@sV9IfV_3RdnXX%BRm!R&d@H;rIymECA90HMS;dGhoPvo(Y;3KDqE->EN@6PEpf=y|Hz@2dt`d#LaS-! zyV&nRFw(blSbX_zplAI;a{$?UPEH~{NoI>7_p+p6^UsRC@4s3KC=w5f*T1D2!ZtOI zwYr1L)YeIXn7=-O9b_W%AUKX?VhoIXm){mw;*$?a$dL<{U4ZaPE$Mu#f_899r&Fz{If?CFA%P zx6lZ`aIwRs8MX#o$M#T6ka8Ca9Pt!l=&rlI)nUg6cg06XS%RLv7s2#Pw@84pW4v%a zUQ|uV6{&!2sLSpR5q{)`qE6Xi7IN}8_2tvVhJ?zoIk|{tLkN!;lJ7%3l8ipZHDcA6+(Or|phSxoJt2sXQ{i)0 zn;R{@YJXMtVOG6ci0@lVxRr=gAMyTO5}inX+kM)n?3~d!Mh(jHxET7G@{6HpIc~Eg z5k~M15xPx!P5kt>-@+mp+kKglaNAHyv8JA~iZ2f>tch-S1t3TsHy}Dm9(^}+XM25R z$96y`)p`ymvt36j-bF?IeS@fTnn&gJX5{?XmggOj?w)83!V#G?NwmiHXn#r>PqEZjIj7A49=Y3O*Yl~O5`?RwIcJRCXJGWRR* zu>{=oYYhTkIqZ2l8(uqhoR%N9)UJEg_MQvQqVS-H6HES>ZdfNTztg3P#vF^;t z&Y}9;XRA&j*KZGvh+p{VeN91p72z z6-sB`#$>(;>pRJgot-n;QCiq}6ut;gMeDm(xN;s|_pBdhtVk8Cw33sQq}(T

)B>2VWhySKq`?ZU^%KtW&Rtd728x--(k88m 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 "$linker" </dev/null diff --git a/crates/snowbound/src/commands.rs b/crates/snowbound/src/commands.rs index 6843120bdc1ebbb5edab45fbdb0de19ffcd9c757..f4413b09a2c528012ced184620cd63578e6096e0 100644 --- a/crates/snowbound/src/commands.rs +++ b/crates/snowbound/src/commands.rs @@ -23,6 +23,9 @@ pub enum Id { PageVersions, CopyPageLink, ShowNotebook, + ExportPdf, + ExportSectionPdf, + Print, Undo, Redo, Cut, @@ -44,7 +47,7 @@ pub enum Id { ActualSize, Sidebar, PageList, - DarkPages, + PagesMatchTheme, FullPageView, /// OneNote's Hide Spelling Errors, which leaves misspelled words unmarked. HideSpelling, @@ -71,6 +74,7 @@ pub enum Id { Eraser, Lasso, Shape(ShapeKind), + SnapToGrid, Toggle(Toggle), Highlight, FontColor, @@ -235,6 +239,15 @@ pub const COMMANDS: &[Command] = &[ NONE, NONE, ), + row!(Id::ExportPdf, "Export as PDF…", NONE, NONE), + row!(Id::ExportSectionPdf, "Export Section as PDF…", NONE, NONE), + // Go to takes OneNote's Ctrl+P, and Pause its Ctrl+Alt+P. + row!( + Id::Print, + "Print…", + &[cmd('p').option().shift()], + &[cmd('p').option().shift()] + ), row!(Id::Undo, "Undo", &[cmd('z')], &[cmd('z')]), row!( Id::Redo, @@ -296,7 +309,7 @@ pub const COMMANDS: &[Command] = &[ ), row!(Id::Sidebar, "Notebook List", &[cmd('s').control()], NONE), row!(Id::PageList, "Page List", NONE, NONE), - row!(Id::DarkPages, "Dark Pages", NONE, NONE), + row!(Id::PagesMatchTheme, "Pages Match UI Theme", NONE, NONE), row!(Id::HideSpelling, "Hide Spelling Errors", NONE, NONE), row!( Id::Spelling, @@ -387,6 +400,7 @@ pub const COMMANDS: &[Command] = &[ row!(Id::Shape(ShapeKind::Arrow), "Arrow", NONE, NONE), row!(Id::Shape(ShapeKind::Rectangle), "Rectangle", NONE, NONE), row!(Id::Shape(ShapeKind::Ellipse), "Oval", NONE, NONE), + row!(Id::SnapToGrid, "Snap To Grid", NONE, NONE), row!(Id::Toggle(Toggle::Bold), "Bold", &[cmd('b')], &[cmd('b')]), row!( Id::Toggle(Toggle::Italic), @@ -773,9 +787,14 @@ impl State { .notebook() .is_some_and(|library| library.catalog().is_some()), ), - Id::NewPage | Id::NewSubpage | Id::CopyPageLink | Id::Find | Id::Search => { - enabled(!modal && session.is_some()) - } + Id::NewPage + | Id::NewSubpage + | Id::CopyPageLink + | Id::Find + | Id::Search + | Id::ExportPdf + | Id::ExportSectionPdf + | Id::Print => enabled(!modal && session.is_some()), Id::PageVersions => session.filter(|_| !modal).map_or( Status { enabled: false, @@ -821,10 +840,14 @@ impl State { Some(crate::pane::Pane::Tags { .. }) )), }, - Id::DarkPages => Status { + Id::PagesMatchTheme => Status { enabled: !modal, checked: Some(!self.light_pages), }, + Id::SnapToGrid => Status { + enabled: !modal, + checked: Some(self.view.snap_to_grid), + }, Id::HideSpelling => Status { enabled: !modal && self.spelling.is_some(), checked: Some(self.hide_spelling), @@ -917,26 +940,6 @@ impl State { Ok(()) } - /// Puts an encoded picture after the caret's paragraph at its size on a 96 dpi screen, - /// as OneNote 2010 inserts one. - pub(crate) fn insert_picture(&mut self, bytes: Vec) -> Result<(), Box> { - let pixels = match draw::RasterImage::measure(&bytes) { - Ok(pixels) => pixels, - Err(_) => { - platform::alert( - "Couldn't insert the picture", - "Choose a PNG, JPEG or GIF picture.", - ); - return Ok(()); - } - }; - let response = self - .view - .insert_picture(bytes, pixels.map(|side| side as f32 * 0.75))?; - self.respond(response); - Ok(()) - } - /// The notebook the open section, or the notebook showing none, belongs to. fn notebook(&self) -> Option<&Arc> { self.session @@ -967,12 +970,10 @@ impl State { return self.paper_page(color, self.view.editor.rule_lines(), None); } Choice::Art(name) => { - let editor = &self.view.editor; - return self.paper_page( - editor.page_color(), - editor.rule_lines(), - Some(name.and_then(canvas::template::find)), - ); + return self.with_art(name.and_then(canvas::template::find), |state, art| { + let editor = &state.view.editor; + state.paper_page(editor.page_color(), editor.rule_lines(), Some(art)) + }); } Choice::RuleLines(lines) => { let lines = lines.map(|index| canvas::template::RULE_LINES[index].1); @@ -1031,6 +1032,14 @@ impl State { platform::reveal(&self.notebook().ok_or("No notebook is open")?.location); return Ok(()); } + Id::ExportPdf | Id::ExportSectionPdf | Id::Print => { + let scope = if id == Id::ExportSectionPdf { + crate::print::Scope::Section + } else { + crate::print::Scope::Page + }; + return self.print(scope, id != Id::Print); + } Id::Undo | Id::Redo => { let response = self.view.undo(id == Id::Redo)?; self.respond(response); @@ -1147,7 +1156,12 @@ impl State { self.save_settings(); return Ok(()); } - Id::DarkPages => { + Id::SnapToGrid => { + self.view.snap_to_grid = !self.view.snap_to_grid; + self.save_settings(); + return Ok(()); + } + Id::PagesMatchTheme => { self.light_pages = !self.light_pages; self.follow_color_scheme(); self.save_settings(); diff --git a/crates/snowbound/src/desktop_linux.rs b/crates/snowbound/src/desktop_linux.rs index 76a9c9428cec15144f9c48ab9af7d59fcbaeaf96..0217033fcbb06960ff67e094435de1c7b9e6f53b 100644 --- a/crates/snowbound/src/desktop_linux.rs +++ b/crates/snowbound/src/desktop_linux.rs @@ -291,8 +291,15 @@ pub fn set_toplevel_icon(window: &Window) -> Option<()> { ]); } } - // Safety: memfd_create returns a new descriptor this File then owns. - let fd = unsafe { libc::memfd_create(c"snowbound-icon".as_ptr(), libc::MFD_CLOEXEC) }; + // Safety: memfd_create returns a new descriptor this File then owns. A system call, as + // glibc wraps it only from 2.27. + let fd = unsafe { + libc::syscall( + libc::SYS_memfd_create, + c"snowbound-icon".as_ptr(), + libc::MFD_CLOEXEC, + ) + } as i32; if fd < 0 { return None; } diff --git a/crates/snowbound/src/guide.rs b/crates/snowbound/src/guide.rs new file mode 100644 index 0000000000000000000000000000000000000000..9733a8c958b19f2a3a4d2692c43ae194689a0548 --- /dev/null +++ b/crates/snowbound/src/guide.rs @@ -0,0 +1,106 @@ +//! The Snowbound Guide, a notebook the app carries (`docs/guide-notebook`). It opens from a +//! copy in the user's documents, so the one inside the app is never edited. + +use crate::{State, platform}; +use notebook::session::Notebook; +use std::{error::Error, path::Path}; + +const NAME: &str = "Snowbound Guide"; +/// Whether the welcome screen offers the guide; off until Clover has read it through. +pub(crate) const OFFERED: bool = false; + +macro_rules! file { + ($name:literal) => { + ( + $name, + include_bytes!(concat!( + "../../../docs/guide-notebook/Snowbound Guide/", + $name + )) + .as_slice(), + ) + }; +} + +const FILES: [(&str, &[u8]); 6] = [ + file!("Open Notebook.onetoc2"), + file!("Getting Started.one"), + file!("Writing & Formatting.one"), + file!("Tags & Search.one"), + file!("Drawing & Recording.one"), + file!("Sharing & Sync.one"), +]; + +impl State { + /// Opens the guide in the user's documents, copying it there first unless it is there. + pub(crate) fn open_guide(&mut self) -> Result<(), Box> { + let documents = platform::documents_dir().ok_or("There is no Documents folder")?; + let folder = std::path::absolute(documents.join(NAME))?; + if !folder.exists() { + copy(&folder, &self.cache)?; + } + self.open_notebook(folder.to_string_lossy().into_owned(), None); + Ok(()) + } +} + +/// Writes the guide to `folder` under a temporary name, then gives it its own, so a copy cut +/// short never passes for the guide. +fn copy(folder: &Path, cache: &Path) -> Result<(), Box> { + let partial = folder.with_file_name(format!("{NAME}.partial")); + if partial.exists() { + std::fs::remove_dir_all(&partial)?; + } + std::fs::create_dir_all(&partial)?; + for (name, bytes) in FILES { + std::fs::write(partial.join(name), bytes)?; + } + // The snowflake tag's art, kept in the notebook as Customize Tags keeps it. + Notebook::open(&partial, cache)?.map_tag_art( + "Snowflake", + 34, + include_bytes!("../assets/tags/snowflake.svg"), + "svg", + )?; + std::fs::rename(&partial, folder)?; + Ok(()) +} + +#[cfg(test)] +mod tests { + use super::*; + + /// The carried files are the committed guide's, and the copy reads as that notebook with + /// its tag art. + #[test] + fn the_guide_copies_whole() { + let root = Path::new(env!("CARGO_MANIFEST_DIR")).join("../../docs/guide-notebook"); + let mut committed: Vec = std::fs::read_dir(root.join(NAME)) + .unwrap() + .map(|entry| entry.unwrap().file_name().to_string_lossy().into_owned()) + .filter(|name| !name.starts_with('.')) + .collect(); + committed.sort(); + let mut carried: Vec = FILES.iter().map(|(name, _)| name.to_string()).collect(); + carried.sort(); + assert_eq!(carried, committed); + + let temporary = + std::env::temp_dir().join(format!("snowbound-guide-{}", std::process::id())); + let _ = std::fs::remove_dir_all(&temporary); + let folder = temporary.join(NAME); + copy(&folder, &temporary.join("cache")).unwrap(); + let notebook = Notebook::open(&folder, temporary.join("cache")).unwrap(); + assert_eq!(notebook.catalog().sections.len(), 5); + let art = notebook.tag_art().unwrap(); + assert_eq!( + art.iter() + .map(|tag| (tag.name.as_str(), tag.shape)) + .collect::>(), + [("Snowflake", 34)] + ); + let committed = std::fs::read_to_string(root.join(NAME).join(".snowbound/tags.json")); + assert!(committed.unwrap().contains(&art[0].art)); + std::fs::remove_dir_all(&temporary).unwrap(); + } +} diff --git a/crates/snowbound/src/linux.rs b/crates/snowbound/src/linux.rs index 360cc5a4873837bc1936f5d733adbbf30b1d15cc..feff722e9b0d715eae0446d9d593451cb6820cf6 100644 --- a/crates/snowbound/src/linux.rs +++ b/crates/snowbound/src/linux.rs @@ -75,6 +75,9 @@ pub fn corner_radius(window: &Window) -> f32 { /// Whether the window erases its own bottom corners to transparent pixels: under winit's /// Adwaita frame on GNOME's Wayland, which draws libadwaita's window edge. Mutter's X11 /// frames stay square at the bottom, as libadwaita's own `ssd-frame` style has them. +/// Winit's theme already holds the window to the app's appearance. +pub fn follow_appearance(_: &Window, _: Theme) {} + pub fn cuts_corners() -> bool { sctk_adwaita::LIBADWAITA_EDGE.load(Ordering::Relaxed) } @@ -197,6 +200,26 @@ impl Clipboard { Self::X11(clipboard) => clipboard.get_text()?, }) } + + pub fn get_files(&mut self) -> Vec { + self.through_x11(|clipboard| clipboard.get().file_list().ok()) + .unwrap_or_default() + } + + pub fn get_picture(&mut self) -> Option> { + self.through_x11(|clipboard| crate::paste::bitmap(clipboard.get_image().ok()?)) + } + + /// Files and pictures come through X11 on Wayland too, whose clipboard Xwayland shares. + fn through_x11( + &mut self, + read: impl FnOnce(&mut arboard::Clipboard) -> Option, + ) -> Option { + match self { + Self::Wayland(_) => read(&mut arboard::Clipboard::new().ok()?), + Self::X11(clipboard) => read(clipboard), + } + } } /// Whether the system draws the title bar: the window manager, or on Wayland the compositor. @@ -254,7 +277,7 @@ fn desktop() -> Desktop { } /// The theme over the window's backdrop, as the kit draws it. -pub fn over_backdrop(theme: ui::Theme) -> ui::Theme { +pub fn over_backdrop(theme: ui::Theme, _: Theme) -> ui::Theme { theme.over_backdrop() } @@ -767,7 +790,7 @@ pub fn cache_dir() -> Option { pub fn smb_mount(path: &std::path::Path) -> Option { let mounts = std::fs::read_to_string("/proc/self/mounts").ok()?; // The mount holding the path is the one at its longest ancestor. - let (source, point, options, within) = mounts + let (source, _, options, within) = mounts .lines() .filter_map(|line| { let mut fields = line.split_whitespace(); @@ -873,6 +896,25 @@ pub fn settings_dir() -> Option { xdg_dir("XDG_CONFIG_HOME", ".config") } +/// The XDG documents folder `user-dirs.dirs` names, or `~/Documents`. +pub fn documents_dir() -> Option { + let home = PathBuf::from(std::env::var_os("HOME")?); + let dirs = xdg_base("XDG_CONFIG_HOME", ".config")?.join("user-dirs.dirs"); + let named = std::fs::read_to_string(dirs).ok().and_then(|text| { + text.lines().find_map(|line| { + let value = line + .strip_prefix("XDG_DOCUMENTS_DIR=")? + .trim() + .trim_matches('"'); + match value.strip_prefix("$HOME") { + Some(rest) => Some(home.join(rest.trim_start_matches('/'))), + None => Some(PathBuf::from(value)).filter(|path| path.is_absolute()), + } + }) + }); + Some(named.unwrap_or_else(|| home.join("Documents"))) +} + /// The app's folder in the XDG base directory `variable` names, or in `fallback` under home. fn xdg_dir(variable: &str, fallback: &str) -> Option { Some(xdg_base(variable, fallback)?.join("snowbound")) diff --git a/crates/snowbound/src/macos.rs b/crates/snowbound/src/macos.rs index 442f85bf7c407779a7e54e45920f8a1b3898372d..ff3297dc8920a5a1807f499e985f74690b1f28ab 100644 --- a/crates/snowbound/src/macos.rs +++ b/crates/snowbound/src/macos.rs @@ -109,6 +109,9 @@ pub fn corner_radius(_: &Window) -> f32 { /// AppKit clips the window's corners itself, except where the OpenGL surface covers /// 10.6's textured window, whose rounded bottom corners the app leaves transparent. +/// Winit's theme already holds the window to the app's appearance. +pub fn follow_appearance(_: &Window, _: winit::window::Theme) {} + pub fn cuts_corners() -> bool { crate::aqua::before_lion() } @@ -185,6 +188,50 @@ impl Clipboard { pub fn get_text(&mut self) -> Result { self.0.get_text() } + + pub fn get_files(&mut self) -> Vec { + self.0.get().file_list().unwrap_or_default() + } + + /// The pasteboard's PNG as copied, keeping its resolution, or else its TIFF as a PNG. + pub fn get_picture(&mut self) -> Option> { + unsafe { + let board: Retained = + msg_send_id![AnyClass::get("NSPasteboard")?, generalPasteboard]; + let data = |kind: &str| -> Option> { + msg_send_id![&board, dataForType: &*NSString::from_str(kind)] + }; + let png = match data("public.png") { + Some(png) => png, + None => tiff_png(&*data("public.tiff")?)?, + }; + Some(ns_data_bytes(&png)) + } + } +} + +/// TIFF `data` as PNG data, keeping its resolution. +unsafe fn tiff_png(data: &AnyObject) -> Option> { + const PNG: usize = 4; // NSBitmapImageFileTypePNG + unsafe { + let rep: Option> = + msg_send_id![AnyClass::get("NSBitmapImageRep")?, imageRepWithData: data]; + let rep = rep?; + let properties: Retained = + msg_send_id![AnyClass::get("NSDictionary")?, dictionary]; + msg_send_id![&rep, representationUsingType: PNG, properties: &*properties] + } +} + +unsafe fn ns_data_bytes(data: &AnyObject) -> Vec { + unsafe { + let length: usize = msg_send![data, length]; + if length == 0 { + return Vec::new(); + } + let bytes: *const u8 = msg_send![data, bytes]; + std::slice::from_raw_parts(bytes, length).to_vec() + } } /// AppKit draws the traffic lights. @@ -246,9 +293,14 @@ pub fn represent(window: &Window, file: Option<&std::path::Path>) { } } -/// The theme over the window's backdrop, as the kit draws it. -pub fn over_backdrop(theme: ui::Theme) -> ui::Theme { - theme.over_backdrop() +/// The theme over the window's backdrop, as the kit draws it. 10.6's textured gradient is +/// light only, so a dark theme paints over it. +pub fn over_backdrop(theme: ui::Theme, appearance: winit::window::Theme) -> ui::Theme { + if crate::aqua::before_lion() && appearance == winit::window::Theme::Dark { + theme + } else { + theme.over_backdrop() + } } /// None: the kit's own menus stand in for AppKit's. @@ -634,6 +686,10 @@ pub fn settings_dir() -> Option { ) } +pub fn documents_dir() -> Option { + Some(std::path::PathBuf::from(std::env::var_os("HOME")?).join("Documents")) +} + /// Asks for a notebook folder or a notebook file with the system's open panel, titled /// `title`. pub fn pick_notebook(title: &str) -> Option { @@ -899,7 +955,10 @@ pub fn edit_date( DateField::Date => NSDatePickerElementFlags::NSDatePickerElementFlagYearMonthDay, DateField::Time => NSDatePickerElementFlags::NSDatePickerElementFlagHourMinute, }); - picker.setPresentsCalendarOverlay(true); + // macOS 10.15's. + if msg_send![&picker, respondsToSelector: sel!(setPresentsCalendarOverlay:)] { + picker.setPresentsCalendarOverlay(true); + } picker.setCalendar(Some(&calendar)); picker.setTimeZone(Some(&calendar.timeZone())); picker.setDateValue(&NSDate::dateWithTimeIntervalSince1970( @@ -1106,10 +1165,21 @@ pub fn text_colors(window: &Window) -> [[f32; 4]; 3] { let previous: Option> = msg_send_id![class, currentAppearance]; let _: () = msg_send![class, setCurrentAppearance: &*appearance]; let space = NSColorSpace::sRGBColorSpace(); + let responds = + |selector: Sel| -> bool { msg_send![NSColor::class(), respondsToSelector: selector] }; + // macOS 14 and 10.14 introduced the first and last. let colors = [ - NSColor::textInsertionPointColor(), + if responds(sel!(textInsertionPointColor)) { + NSColor::textInsertionPointColor() + } else { + NSColor::textColor() + }, NSColor::selectedTextBackgroundColor(), - NSColor::unemphasizedSelectedTextBackgroundColor(), + if responds(sel!(unemphasizedSelectedTextBackgroundColor)) { + NSColor::unemphasizedSelectedTextBackgroundColor() + } else { + msg_send_id![NSColor::class(), secondarySelectedControlColor] + }, ] .map(|color| { let color = color diff --git a/crates/snowbound/src/main.rs b/crates/snowbound/src/main.rs index 684f1eafae212644f3c8891d1378c8e3885a5a98..3de2a1c0ccc224f4170877300e062c5a8e27da92 100644 --- a/crates/snowbound/src/main.rs +++ b/crates/snowbound/src/main.rs @@ -10,6 +10,7 @@ mod conflict_render; #[cfg(target_os = "linux")] #[path = "desktop_linux.rs"] mod desktop; +mod guide; mod history; #[cfg_attr(not(target_os = "macos"), path = "icloud_linux.rs")] #[cfg_attr(target_os = "macos", path = "icloud_macos.rs")] @@ -29,10 +30,16 @@ mod navigation; mod options; mod palette; mod pane; +mod paste; #[cfg_attr(target_os = "linux", path = "linux.rs")] #[cfg_attr(target_os = "macos", path = "macos.rs")] #[cfg_attr(windows, path = "windows.rs")] mod platform; +mod print; +#[cfg_attr(target_os = "linux", path = "print_linux.rs")] +#[cfg_attr(target_os = "macos", path = "print_macos.rs")] +#[cfg_attr(windows, path = "print_windows.rs")] +mod printer; mod recording; mod rename; mod screenshot; @@ -96,6 +103,9 @@ const TAB_ROW: f32 = 28.0; /// Width of the section colour around the page, and the rows' margin at the window's sides. const FRAME: f32 = 6.0; const PAGE_LIST: f32 = 240.0; +/// The least window: the page list and a page beside it. The window widens past it to the +/// toolbar's narrowest row, the window's controls beside it. +const MIN_SIZE: [f32; 2] = [600.0, 400.0]; /// Extensions of the pictures Insert, Picture offers: those the page both stores and draws. const PICTURE_TYPES: [&str; 4] = ["png", "jpg", "jpeg", "gif"]; /// Font sizes the size box offers, OneNote's list in points. @@ -163,7 +173,8 @@ const PILL_MARGIN: f32 = 3.0; const DATE_UNCHOSEN: &str = "Choose another date or time."; const DATE_OUT_OF_RANGE: &str = "This date is outside the notebook's supported range."; -#[derive(Debug)] +type Continuation = Box Result<(), Box> + Send>; + enum UserEvent { Quit, /// Text AppKit inserts outside key events, such as the character palette's. @@ -187,6 +198,8 @@ enum UserEvent { /// The desktop's colours changed, where the window system doesn't say so itself. #[cfg_attr(target_os = "macos", allow(dead_code))] Appearance, + /// What follows work a thread of its own finished, run on the event loop's. + Then(Continuation), /// The iCloud account signed out, signed in or switched, or iCloud Drive was turned off. #[cfg_attr(not(target_os = "macos"), allow(dead_code))] ICloudAccount, @@ -209,11 +222,21 @@ impl Clipboard { Ok(()) } - fn get_text(&mut self) -> Result> { - Ok(match self { - Self::System(clipboard) => clipboard.get_text()?, - Self::Memory(held) => held.clone(), - }) + fn pasted(&mut self) -> Option { + match self { + Self::System(clipboard) => { + let files = clipboard.get_files(); + if !files.is_empty() { + Some(paste::Pasted::Files(files)) + } else if let Some(text) = clipboard.get_text().ok().filter(|text| !text.is_empty()) + { + Some(paste::Pasted::Text(text)) + } else { + clipboard.get_picture().map(paste::Pasted::Picture) + } + } + Self::Memory(held) => Some(paste::Pasted::Text(held.clone())), + } } } @@ -226,6 +249,8 @@ impl std::task::Wake for Redraw { #[derive(Debug)] enum Replay { Input(ui::Event), + /// A trackpad pinch scaling the page by the factor. + Pinch(f32), /// Paints the next frame into a PNG as well as the window. Snapshot(PathBuf), /// Writes the window's accessibility tree as text. @@ -496,6 +521,8 @@ enum Command { NewNotebook, /// Opens the notebooks in the app's iCloud Drive folder, making one there if it has none. UseICloud, + /// Opens the Snowbound Guide from the user's documents, copying it there first. + OpenGuide, /// Adds Snowbound to the app menu. #[cfg(target_os = "linux")] Install, @@ -622,6 +649,14 @@ struct State { hide_spelling: bool, /// Options' "Use pen pressure sensitivity": a tablet pen's strokes follow its pressure. pen_pressure: bool, + /// Options' Default font, which new text and titles take. + default_font: settings::DefaultFont, + /// Options' "Page tabs appear on the left". + page_tabs_left: bool, + /// Options' "Navigation bar appears on the left" off: the notebooks on the right. + navigation_bar_right: bool, + /// Servers Open Notebook from Server signed in to, latest first. + servers: Vec, /// The word the Spelling pane shows. correction: Option, /// The strip's fill with the window focused and not, continuing the system's title bar. @@ -681,6 +716,8 @@ struct State { initial_layouts: Vec<(onestore::ExGuid, onestore::document::Layout)>, initial_date: Option, occluded: bool, + /// The least width last given the window. + min_width: f32, ime_allowed: bool, clipboard: Clipboard, access_adapter: accesskit_winit::Adapter, @@ -746,8 +783,7 @@ impl State { Input::Notebooks { .. } => "Snowbound".into(), }) .with_inner_size(LogicalSize::new(1180.0, 760.0)) - // The page list and a page beside it, under the toolbar's text group. - .with_min_inner_size(LogicalSize::new(600.0, 400.0)), + .with_min_inner_size(LogicalSize::new(MIN_SIZE[0], MIN_SIZE[1])), )?, ); platform::install_title_bar(&window); @@ -872,6 +908,7 @@ impl State { .color_scheme .theme() .unwrap_or_else(|| platform::appearance(&window)); + platform::follow_appearance(&window, appearance); let mut ui = Ui::new( theme(appearance, stored.light_pages, backdrop), platform::double_click_interval(), @@ -975,6 +1012,7 @@ impl State { initial_date, initial_layouts, occluded: false, + min_width: MIN_SIZE[0], ime_allowed: true, clipboard, loads: mpsc::channel(), @@ -991,8 +1029,13 @@ impl State { spelling, hide_spelling: stored.hide_spelling, pen_pressure: !stored.ignore_pen_pressure, + default_font: stored.default_font, + page_tabs_left: stored.page_tabs_left, + navigation_bar_right: stored.navigation_bar_right, + servers: stored.servers, correction: None, }; + state.view.snap_to_grid = !stored.ignore_grid; // A notebook opened from its server that couldn't sign in asks to, as the Finder does. let unsigned = state.notebooks.iter().find(|library| { library.notebook.is_err() && library::server_address(&library.location).is_some() @@ -1119,6 +1162,7 @@ impl State { /// Takes `appearance`'s colours. fn set_appearance(&mut self, appearance: winit::window::Theme) { + platform::follow_appearance(&self.window, appearance); self.ui.theme = theme(appearance, self.light_pages, self.surface.translucent()); self.titlebar = platform::titlebar(appearance) .filter(|_| !self.surface.translucent()) @@ -1619,11 +1663,11 @@ impl State { role: Some(accesskit::Role::Toolbar), ..Spec::default() }; - if strip_row { - self.ui.open_as(strip(), spec); + let row = if strip_row { + self.ui.open_as(strip(), spec) } else { - self.ui.open("toolbar", spec); - } + self.ui.open("toolbar", spec) + }; let lead = if title { platform::LEADING } else { FRAME }; self.ui.leaf( "lead", @@ -1633,7 +1677,22 @@ impl State { }, ); if tools { + // The groups fold in the room the window's controls leave, and whatever still + // overflows is cut there, so the controls always show. + let edge = (TITLE - ui::shell::TOOL) / 2.0; + self.ui.open( + "tools", + Spec { + flags: Flags::CLIP, + size: [fill(), px(TITLE)], + pad: [0.0, edge], + offset: [0.0, -edge], + gap: GAP, + ..Spec::default() + }, + ); self.tools(theme); + self.ui.close(); } else { self.ui.leaf( "space", @@ -1654,6 +1713,15 @@ impl State { }, ); self.ui.close(); + let narrowest = self + .ui + .narrowest(row) + .map_or(MIN_SIZE[0], |row| row.ceil().max(MIN_SIZE[0])); + if narrowest != self.min_width { + self.min_width = narrowest; + self.window + .set_min_inner_size(Some(LogicalSize::new(narrowest, MIN_SIZE[1]))); + } Ok(()) } @@ -2146,13 +2214,17 @@ impl State { ) .or(choice); // The Draw tab's tools, which Insert's menus list for when they fold, before Insert. + // OneNote's shape gallery ends with Snap To Grid. let shapes = [ ShapeKind::Line, ShapeKind::Arrow, ShapeKind::Rectangle, ShapeKind::Ellipse, ] - .map(|kind| Run(Cmd::Shape(kind))); + .map(|kind| Run(Cmd::Shape(kind))) + .into_iter() + .chain([Rule, Run(Cmd::SnapToGrid)]) + .collect::>(); let drawing = [ Run(Cmd::SelectType), Open("pen", Cmd::Pen), @@ -2161,7 +2233,7 @@ impl State { Rule, ] .into_iter() - .chain(shapes); + .chain(shapes.iter().copied()); let inserted = [Cmd::Picture, Cmd::Link, Cmd::Date, Cmd::Equation]; let more = [ Cmd::ScreenClipping, @@ -2320,7 +2392,7 @@ impl State { let views = [ Run(Cmd::Sidebar), Run(Cmd::PageList), - Run(Cmd::DarkPages), + Run(Cmd::PagesMatchTheme), Run(Cmd::FullPageView), Rule, Run(Cmd::HideSpelling), @@ -2702,6 +2774,7 @@ impl State { Command::OpenFromServer(location) => self.open_server(location.as_deref()), Command::NewNotebook => self.new_notebook()?, Command::UseICloud => self.use_icloud()?, + Command::OpenGuide => self.open_guide()?, #[cfg(target_os = "linux")] Command::Install => desktop::install(), Command::CloseNotebook(library) => self.close_notebook(&library), @@ -2723,12 +2796,7 @@ impl State { Command::Template(choice) => self.apply_template(choice)?, Command::Page(Request::EditDate(field)) => self.edit_date(field)?, Command::Page(Request::Copy(text)) => self.clipboard.set_text(text)?, - Command::Page(Request::Paste) => { - let text = self.clipboard.get_text()?; - let language = canvas::language::lcid(&platform::input_language()); - let response = self.view.paste(&text, language)?; - self.respond(response); - } + Command::Page(Request::Paste) => self.paste()?, Command::Page(Request::OpenLink(address)) => self.open_link(&address)?, Command::Page(Request::OpenAttachment(file)) => self.open_attachment(&file)?, Command::Page(Request::Play { file, at_ms }) => self.play(&file, at_ms)?, @@ -3608,7 +3676,14 @@ impl State { /// Zooms the page by `factor` about the pointer, when it is over the page. fn pinch(&mut self, factor: f32) -> Result<(), Box> { if self.over_page() { - let response = self.view.pinch(factor)?; + // The pointer here, as the page's own lags by the moves queued for the next frame. + let [left, top, ..] = self.ui.rect(page()).unwrap_or_default(); + let scale = self.ui.scale(); + let anchor = [ + (self.pointer[0] - left) * scale, + (self.pointer[1] - top) * scale, + ]; + let response = self.view.pinch(factor, anchor)?; self.respond(response); } Ok(()) @@ -3706,7 +3781,7 @@ fn theme(appearance: winit::window::Theme, light_pages: bool, backdrop: bool) -> [theme.paper, theme.paper_ink] = [light.paper, light.paper_ink]; } if backdrop { - platform::over_backdrop(theme) + platform::over_backdrop(theme, appearance) } else { theme } @@ -4921,6 +4996,15 @@ impl ApplicationHandler for App { self.close(event_loop); return; } + UserEvent::Then(then) => { + if let Some(state) = &mut self.state { + if let Err(error) = then(state) { + eprintln!("{error}"); + } + state.window.request_redraw(); + } + return; + } UserEvent::ICloudAccount => { if let Some(state) = &mut self.state { state.icloud_account_changed(); @@ -4966,6 +5050,11 @@ impl ApplicationHandler for App { if let Some(state) = &mut self.state { match replay { Replay::Input(event) => state.input(event), + Replay::Pinch(factor) => { + if let Err(error) = state.pinch(factor) { + eprintln!("{error}"); + } + } Replay::Snapshot(path) => state.snapshot = Some(path), Replay::Accessibility(path) => { if let Err(error) = state.write_accessibility(&path) { @@ -5202,16 +5291,13 @@ impl ApplicationHandler for App { fn write_png(path: &Path, size: [u32; 2], pixels: &[u8]) -> Result<(), Box> { let partial = path.with_extension("partial"); - let mut encoder = png::Encoder::new(std::fs::File::create(&partial)?, size[0], size[1]); - encoder.set_color(png::ColorType::Rgba); - encoder.set_depth(png::BitDepth::Eight); - encoder.write_header()?.write_image_data(pixels)?; + std::fs::write(&partial, paste::png(size, pixels)?)?; std::fs::rename(partial, path)?; Ok(()) } /// Feeds a development script to the window from another thread, one command per line -/// in logical pixels: `move X Y`, `press [right]`, `release [right]`, `wheel DX DY`, `key NAME`, `type +/// in logical pixels: `move X Y`, `press [right]`, `release [right]`, `wheel DX DY`, `pinch FACTOR`, `key NAME`, `type /// TEXT`, `modifiers [shift] [command]`, `wait MILLISECONDS`, `snapshot PNG_PATH`, /// `accessibility TEXT_PATH`, `appearance light|dark`, `resize WIDTH HEIGHT` and `quit`. fn replay(script: String, proxy: EventLoopProxy) -> Result<(), Box> { @@ -5241,6 +5327,7 @@ fn replay(script: String, proxy: EventLoopProxy) -> Result<(), Box None, level => Some(level.parse()?), }))), + "pinch" => Ok(Replay::Pinch(rest.parse()?)), "press" => Ok(Replay::Input(button(true))), "release" => Ok(Replay::Input(button(false))), "key" => Ok(Replay::Input(ui::Event::Key { diff --git a/crates/snowbound/src/manage.rs b/crates/snowbound/src/manage.rs index 0b074803640a74fd5b1ecdf5a2456659b43fc7b6..eedc6bb5272acdc0401b01f9bfe1298a8ebe988a 100644 --- a/crates/snowbound/src/manage.rs +++ b/crates/snowbound/src/manage.rs @@ -7,7 +7,7 @@ use notebook::session::Notebook; use onestore::{ ExGuid, PageCreation, PageEdit, op::{Edit, Op, PageOp, SectionOp}, - page::{Page, PageObject}, + page::{Image, Page, PageObject}, }; use std::{error::Error, sync::Arc}; @@ -124,24 +124,59 @@ impl State { &mut self, choice: crate::templates::Choice, ) -> Result<(), Box> { - self.persist()?; - let session = self.session.as_ref().ok_or("No section is open")?; - let ops = template_ops(&session.section.page(session.space)?, choice)?; - self.edit_page(ops) + use crate::templates::Choice; + let template = match choice { + Choice::Template(name) => { + Some(canvas::template::find(name).ok_or("That template is not available")?) + } + _ => None, + }; + self.with_art(template, move |state, art| { + state.persist()?; + let session = state.session.as_ref().ok_or("No section is open")?; + let ops = template_ops(&session.section.page(session.space)?, choice, art)?; + state.edit_page(ops) + }) + } + + /// Calls `then` with `template`'s pictures, or none without one. Rasterizing and encoding + /// them takes seconds on a slow machine, so they are made on a thread of their own, and + /// `then` runs on this one after if the page they were chosen for is still open. + pub(crate) fn with_art( + &mut self, + template: Option<&'static Template>, + then: impl FnOnce(&mut State, Vec) -> Result<(), Box> + Send + 'static, + ) -> Result<(), Box> { + let Some(template) = template else { + return then(self, Vec::new()); + }; + let space = self.session.as_ref().ok_or("No section is open")?.space; + let proxy = self.proxy.clone(); + std::thread::spawn(move || { + let art = template.pictures().map_err(|error| error.to_string()); + let _ = proxy.send_event(crate::UserEvent::Then(Box::new(move |state| { + if state + .session + .as_ref() + .is_some_and(|open| open.space == space) + { + then(state, art?) + } else { + Ok(()) + } + }))); + }); + Ok(()) } /// View, Page Color and Rule Lines: gives the open page `color`, a COLORREF, - /// `rule_lines` and, when given, `template`'s art or none in place of the art it had, as - /// one undo step. + /// `rule_lines` and, when given, `art` in place of the art it had, as one undo step. pub(crate) fn paper_page( &mut self, color: Option, rule_lines: Option, - art: Option>, + art: Option>, ) -> Result<(), Box> { - let art = art - .map(|template| template.map_or(Ok(Vec::new()), Template::pictures)) - .transpose()?; let response = self.view.set_paper(color, rule_lines, art)?; self.respond(response); Ok(()) @@ -507,14 +542,11 @@ impl State { pub fn template_ops( page: &Page, choice: crate::templates::Choice, + art: Vec, ) -> Result, Box> { use crate::templates::Choice; let mut ops = match choice { - Choice::Template(name) => art_ops( - page, - Some(canvas::template::find(name).ok_or("That template is not available")?), - )?, - Choice::Color(_) => art_ops(page, None)?, + Choice::Template(_) | Choice::Color(_) => art_ops(page, art), Choice::More | Choice::Dismiss | Choice::Colors => return Ok(Vec::new()), }; match choice { @@ -538,9 +570,9 @@ pub fn template_ops( Ok(ops) } -/// The ops giving `page` `template`'s art (OneNote's pictures' places, our recreations' -/// bytes), or none, in place of the background pictures it had. -pub fn art_ops(page: &Page, template: Option<&Template>) -> Result, Box> { +/// The ops giving `page` `art`, a template's pictures, in place of the background pictures +/// it had. +fn art_ops(page: &Page, art: Vec) -> Vec { let mut ops: Vec = page .objects .iter() @@ -560,13 +592,11 @@ pub fn art_ops(page: &Page, template: Option<&Template>) -> Result, _ => true, }) .map(PageObject::id); - for image in template.map_or(Ok(Vec::new()), Template::pictures)? { - ops.push(PageOp::Add { - object: PageObject::Image(image), - before: under, - }); - } - Ok(ops) + ops.extend(art.into_iter().map(|image| PageOp::Add { + object: PageObject::Image(image), + before: under, + })); + ops } #[cfg(test)] @@ -695,7 +725,11 @@ mod tests { unreachable!() }; let background = |space: ExGuid, choice: Choice| { - template_ops(&page(&file, space), choice) + let art = match choice { + Choice::Template(name) => canvas::template::find(name).unwrap().pictures().unwrap(), + _ => Vec::new(), + }; + template_ops(&page(&file, space), choice, art) .unwrap() .into_iter() .map(|op| Op::Page { space, op }) diff --git a/crates/snowbound/src/media_macos.rs b/crates/snowbound/src/media_macos.rs index 8d824fbe7ce28b4b0ce3ce50ab741829bd754de8..6ac39e6f8f33f91cf68bc02282c02abc61cb3d18 100644 --- a/crates/snowbound/src/media_macos.rs +++ b/crates/snowbound/src/media_macos.rs @@ -232,9 +232,14 @@ fn refused(device: &str, pane: &str) -> String { } /// Whether the system refused media of `kind`: AVAuthorizationStatusRestricted or Denied. +/// Before macOS 10.14 it never asks, and nothing is refused. fn denied(kind: &NSString) -> bool { - let status: isize = - unsafe { msg_send![class("AVCaptureDevice"), authorizationStatusForMediaType: kind] }; + let device = class("AVCaptureDevice"); + let selector = sel!(authorizationStatusForMediaType:); + if !unsafe { msg_send![device, respondsToSelector: selector] } { + return false; + } + let status: isize = unsafe { msg_send![device, authorizationStatusForMediaType: kind] }; matches!(status, 1 | 2) } diff --git a/crates/snowbound/src/menubar.rs b/crates/snowbound/src/menubar.rs index 2333437b46bc17de1baf47f1ff31e9ec1382c712..bb0175d6178053e1b92b132c05a20f3fae8efd1f 100644 --- a/crates/snowbound/src/menubar.rs +++ b/crates/snowbound/src/menubar.rs @@ -66,6 +66,11 @@ const MENUS: &[Item] = &[ C(Id::PageVersions), C(Id::CopyPageLink), C(Id::ShowNotebook), + S, + C(Id::ExportPdf), + C(Id::ExportSectionPdf), + S, + C(Id::Print), ], ), Item::Menu( @@ -111,7 +116,7 @@ const MENUS: &[Item] = &[ C(Id::PageList), S, C(Id::PageColor), - C(Id::DarkPages), + C(Id::PagesMatchTheme), C(Id::HideSpelling), C(Id::Spelling), ], diff --git a/crates/snowbound/src/options.rs b/crates/snowbound/src/options.rs index d23763de50f3993487ab351805672e2a9f923251..2b53675799cc90a9c48d51a517c5d2abff774825 100644 --- a/crates/snowbound/src/options.rs +++ b/crates/snowbound/src/options.rs @@ -164,13 +164,13 @@ impl State { match options.page { Page::General => { heading(ui, &theme, "User Interface Options"); - field(ui, "Color scheme:", |ui| { + field(ui, "Appearance:", |ui| { let combo = ui.id("combo"); let current = SCHEMES .iter() .find(|(scheme, _)| *scheme == options.color_scheme) .map_or("", |(_, name)| name); - ui::shell::combo(ui, "combo", "Color scheme", current, 140.0, schemes(), true); + ui::shell::combo(ui, "combo", "Appearance", current, 140.0, schemes(), true); let items = SCHEMES.map(|(scheme, name)| Item { text: name, checked: Some(scheme == options.color_scheme), @@ -244,16 +244,10 @@ impl State { } Page::Display => { heading(ui, &theme, "Display"); - let dark = !options.light_pages; - if ui::check_box( - ui, - "dark-pages", - "Pages appear dark in the Dark color scheme", - dark, - ) - .clicked + let matching = !options.light_pages; + if ui::check_box(ui, "pages-match-theme", "Pages match UI theme", matching).clicked { - options.light_pages = dark; + options.light_pages = matching; } } Page::Advanced => { diff --git a/crates/snowbound/src/paste.rs b/crates/snowbound/src/paste.rs new file mode 100644 index 0000000000000000000000000000000000000000..b459308c324e58a39f05f70b08acb0046855e5d2 --- /dev/null +++ b/crates/snowbound/src/paste.rs @@ -0,0 +1,184 @@ +//! Pictures and files from the clipboard, and pictures inserted, as OneNote 2010 places them. + +use crate::{State, platform}; +use std::{error::Error, path::PathBuf}; + +/// What Paste takes from the clipboard. Files come first, as Finder also offers their names +/// as text and their icons as pictures; text before a picture, as Office and browsers offer +/// a picture of copied text beside it. +pub(crate) enum Pasted { + Files(Vec), + Text(String), + Picture(Vec), +} + +impl State { + pub(crate) fn paste(&mut self) -> Result<(), Box> { + match self.clipboard.pasted() { + Some(Pasted::Files(paths)) => { + for path in paths { + // OneNote 2010 pastes a picture file as the picture (lab, 2026-09-30). + match std::fs::read(&path) { + Ok(bytes) if draw::RasterImage::measure(&bytes).is_ok() => { + self.insert_picture(bytes)? + } + _ => self.attach(&path, None)?, + } + } + } + Some(Pasted::Text(text)) => { + let language = canvas::language::lcid(&platform::input_language()); + let response = self.view.paste(&text, language)?; + self.respond(response); + } + Some(Pasted::Picture(bytes)) => self.insert_picture(bytes)?, + None => {} + } + Ok(()) + } + + /// Puts an encoded picture at the caret at the size its resolution gives it, as OneNote + /// 2010 inserts and pastes one. + pub(crate) fn insert_picture(&mut self, bytes: Vec) -> Result<(), Box> { + let Ok(pixels) = draw::RasterImage::measure(&bytes) else { + platform::alert( + "Couldn't insert the picture", + "Choose a PNG, JPEG or GIF picture.", + ); + return Ok(()); + }; + let size = picture_size(&bytes, pixels); + let response = self.view.insert_picture(bytes, size)?; + self.respond(response); + Ok(()) + } +} + +/// A picture's size in points: its pixels at the resolution it declares, or at 96 dpi +/// without one, as OneNote 2010 sizes inserted and pasted pictures and pasted bitmaps +/// (lab, 2026-09-30). +fn picture_size(encoded: &[u8], pixels: [u32; 2]) -> [f32; 2] { + let dpi = resolution(encoded).unwrap_or([96.0; 2]); + [0, 1].map(|axis| pixels[axis] as f32 * 72.0 / dpi[axis]) +} + +/// Dots per inch from a PNG's `pHYs` or a JPEG's JFIF density, where they give one. +fn resolution(encoded: &[u8]) -> Option<[f32; 2]> { + let dpi = if let Some(mut chunks) = encoded.strip_prefix(b"\x89PNG\r\n\x1a\n") { + loop { + let length = u32::from_be_bytes(chunks.get(..4)?.try_into().ok()?) as usize; + let kind = chunks.get(4..8)?; + let data = chunks.get(8..8 + length)?; + if kind == b"IDAT" { + return None; + } + // Unit 1 is the metre. + if kind == b"pHYs" && data.len() == 9 && data[8] == 1 { + let per_metre = + |at: usize| u32::from_be_bytes(data[at..at + 4].try_into().unwrap()); + break [per_metre(0), per_metre(4)].map(|dots| dots as f32 * 0.0254); + } + chunks = chunks.get(12 + length..)?; + } + } else { + // Length, identifier, version, units, then the densities. + let app0 = encoded.strip_prefix(b"\xff\xd8\xff\xe0")?.get(..14)?; + if &app0[2..7] != b"JFIF\0" { + return None; + } + let density = |at: usize| u16::from_be_bytes([app0[at], app0[at + 1]]) as f32; + let dots = [density(10), density(12)]; + match app0[9] { + 1 => dots, + 2 => dots.map(|per_cm| per_cm * 2.54), + _ => return None, + } + }; + dpi.iter().all(|dpi| *dpi > 0.0).then_some(dpi) +} + +/// A bitmap from the clipboard as the PNG a page stores, without a resolution, so it takes +/// 96 dpi as OneNote 2010 gives a pasted bitmap. +#[cfg(not(target_os = "macos"))] +pub(crate) fn bitmap(image: arboard::ImageData) -> Option> { + png( + [image.width, image.height].map(|side| side as u32), + &image.bytes, + ) + .ok() +} + +/// Straight RGBA pixels as a PNG without a resolution. +pub(crate) fn png(size: [u32; 2], rgba: &[u8]) -> Result, png::EncodingError> { + let mut bytes = Vec::new(); + let mut encoder = png::Encoder::new(&mut bytes, size[0], size[1]); + encoder.set_color(png::ColorType::Rgba); + encoder.set_depth(png::BitDepth::Eight); + encoder.write_header()?.write_image_data(rgba)?; + Ok(bytes) +} + +#[cfg(test)] +mod tests { + use super::*; + + fn png_at(pixels_per_metre: Option) -> Vec { + let mut bytes = Vec::new(); + let mut encoder = png::Encoder::new(&mut bytes, 200, 100); + encoder.set_color(png::ColorType::Rgba); + encoder.set_pixel_dims(pixels_per_metre.map(|dots| png::PixelDimensions { + xppu: dots, + yppu: dots, + unit: png::Unit::Meter, + })); + encoder + .write_header() + .unwrap() + .write_image_data(&[0; 200 * 100 * 4]) + .unwrap(); + bytes + } + + fn jfif(units: u8, density: u16) -> Vec { + let mut bytes = b"\xff\xd8\xff\xe0\x00\x10JFIF\0\x01\x01".to_vec(); + bytes.push(units); + bytes.extend(density.to_be_bytes()); + bytes.extend(density.to_be_bytes()); + bytes.extend([0, 0]); + bytes + } + + fn close(size: [f32; 2], expected: [f32; 2]) -> bool { + (0..2).all(|axis| (size[axis] - expected[axis]).abs() < 0.01) + } + + /// OneNote 2010 read these back from a 200 by 100 pixel picture that GDI+ saved at 72 + /// and 48 dpi (lab, 2026-09-30). + #[test] + fn pictures_take_the_size_their_resolution_gives() { + let pixels = [200, 100]; + let size = |bytes: &[u8]| picture_size(bytes, pixels); + assert!(close(size(&png_at(Some(2834))), [200.0456, 100.0228])); + assert!(close(size(&png_at(Some(1889))), [300.1212, 150.0606])); + assert!(close(size(&png_at(None)), [150.0, 75.0])); + assert!(close(size(&jfif(1, 48)), [300.0, 150.0])); + assert!(close(size(&jfif(2, 20)), [283.4646, 141.7323])); + assert!(close(size(&jfif(0, 1)), [150.0, 75.0])); + assert!(close(size(&jfif(1, 0)), [150.0, 75.0])); + assert!(close(size(b"GIF89a"), [150.0, 75.0])); + } + + #[test] + fn a_pasted_bitmap_is_stored_as_a_png_at_96_dpi() { + let rgba: Vec = (0..3 * 2 * 4).map(|byte| byte as u8).collect(); + let encoded = png([3, 2], &rgba).unwrap(); + assert_eq!(draw::RasterImage::measure(&encoded).unwrap(), [3, 2]); + assert!(close(picture_size(&encoded, [3, 2]), [2.25, 1.5])); + let mut reader = png::Decoder::new(std::io::Cursor::new(&encoded)) + .read_info() + .unwrap(); + let mut decoded = vec![0; reader.output_buffer_size().unwrap()]; + reader.next_frame(&mut decoded).unwrap(); + assert_eq!(decoded, rgba); + } +} diff --git a/crates/snowbound/src/print.rs b/crates/snowbound/src/print.rs new file mode 100644 index 0000000000000000000000000000000000000000..870e426823796a9887dbce08aa03198711ed5539 --- /dev/null +++ b/crates/snowbound/src/print.rs @@ -0,0 +1,118 @@ +//! File, Print… and Export as PDF…: the open page, or the whole section, laid on paper as +//! OneNote 2010 prints it (`canvas::print`), then handed to the system's printing or saved. + +use crate::{State, UserEvent, platform, printer}; +use onestore::page::Page; +use std::{error::Error, path::PathBuf, sync::Arc}; + +#[derive(Clone, Copy, PartialEq, Eq)] +pub enum Scope { + Page, + Section, +} + +impl State { + /// Prints `scope` through the system's print dialog, or with `export` saves it as a PDF + /// where the user chooses. Pages are laid out on a thread of their own. + pub(crate) fn print(&mut self, scope: Scope, export: bool) -> Result<(), Box> { + let session = self.session.as_ref().ok_or("No section is open")?; + let section = session.tabs[session.tab].name.clone(); + // The open page as the editor holds it; the section's others as stored. + let open = (session.space, self.view.editor.page()?); + let spaces: Vec<_> = match scope { + Scope::Page => vec![session.space], + Scope::Section => session.pages.iter().map(|(space, ..)| *space).collect(), + }; + let title = match scope { + Scope::Page => open.1.title.clone(), + Scope::Section => section.clone(), + }; + let destination = if export { + let name = format!("{}.pdf", file_name(&title)); + let Some(mut path) = platform::pick_new("Export as PDF", &name, "Export", None) else { + return Ok(()); + }; + if path.extension().is_none() { + path.set_extension("pdf"); + } + Some(path) + } else { + None + }; + let replica = Arc::clone(session.section.replica()); + let layouts = Arc::clone(&self.layouts); + let proxy = self.proxy.clone(); + let paper = printer::paper(); + std::thread::spawn(move || { + let made = (|| -> Result, Box> { + let mut open = Some(open); + let pages = spaces + .into_iter() + .map(|space| match open.take_if(|(shown, _)| *shown == space) { + Some((_, page)) => Ok(page), + None => replica.page(space).map_err(Into::into), + }) + .collect::, Box>>()?; + let mut engine = layouts.lock().map_err(|_| "Page layout failed")?; + Ok(canvas::print::pdf(pages, &mut engine, paper, §ion)?) + })(); + let done = made.and_then(|pdf| match &destination { + Some(path) => std::fs::write(path, pdf).map(|()| None).map_err(Into::into), + None => Ok(Some(pdf)), + }); + let failed = if export { + "Couldn't export the PDF" + } else { + "Couldn't print" + }; + let done = done.map_err(|error| error.to_string()); + let _ = proxy.send_event(UserEvent::Then(Box::new(move |state| { + match done { + Ok(Some(pdf)) => printer::print(&state.window, &pdf, &title), + Ok(None) => Ok(()), + Err(error) => Err(error.into()), + } + .inspect_err(|error| platform::alert(failed, &error.to_string())) + }))); + }); + Ok(()) + } +} + +/// `title` as a file name: without the characters Windows and macOS refuse in one. +fn file_name(title: &str) -> String { + let name: String = title + .chars() + .map(|c| match c { + '/' | '\\' | ':' | '*' | '?' | '"' | '<' | '>' | '|' => '-', + c if c.is_control() => ' ', + c => c, + }) + .collect(); + match name.trim() { + "" => "Untitled".to_owned(), + name => name.to_owned(), + } +} + +/// A PDF waiting for a system viewer or print service, in the cache folder under `title`. +pub(crate) fn spooled(pdf: &[u8], title: &str) -> Result> { + let folder = platform::cache_dir() + .unwrap_or_else(std::env::temp_dir) + .join("Printing"); + std::fs::create_dir_all(&folder)?; + let path = folder.join(format!("{}.pdf", file_name(title))); + std::fs::write(&path, pdf)?; + Ok(path) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn titles_become_file_names() { + assert_eq!(file_name("Notes: 3/4"), "Notes- 3-4"); + assert_eq!(file_name(" "), "Untitled"); + } +} diff --git a/crates/snowbound/src/print_linux.rs b/crates/snowbound/src/print_linux.rs new file mode 100644 index 0000000000000000000000000000000000000000..a65fa959afc4601a017a87a8689bfdc3df37f677 --- /dev/null +++ b/crates/snowbound/src/print_linux.rs @@ -0,0 +1,110 @@ +//! Printing on Linux: the desktop's print dialog through the XDG print portal, which prints +//! the PDF itself; without a portal the PDF opens in the desktop's viewer to print from. + +use std::{collections::HashMap, error::Error, time::Duration}; +use winit::window::Window; +use zbus::zvariant::{Fd, OwnedValue, Value}; + +/// Countries whose paper is US Letter; everywhere else prints on A4. +const LETTER_COUNTRIES: [&str; 16] = [ + "US", "CA", "MX", "PR", "PH", "CL", "CO", "VE", "GT", "CR", "PA", "DO", "SV", "NI", "HN", "BZ", +]; + +/// The paper of the locale's country, as `LC_PAPER` names it. +pub fn paper() -> [f32; 2] { + let locale = ["LC_ALL", "LC_PAPER", "LANG"] + .into_iter() + .find_map(|name| std::env::var(name).ok().filter(|value| !value.is_empty())) + .unwrap_or_default(); + paper_of(&locale) +} + +/// The paper of `locale`'s country, such as `en_GB.UTF-8`'s. +fn paper_of(locale: &str) -> [f32; 2] { + let country = locale + .split(['.', '@']) + .next() + .and_then(|language| language.split('_').nth(1)) + .unwrap_or("US"); + if LETTER_COUNTRIES.contains(&country) { + canvas::print::LETTER + } else { + canvas::print::A4 + } +} + +/// Asks the print portal for the print dialog, then prints `pdf` as it was set up; the +/// dialog belongs to the portal, so a thread of its own waits on it. +pub fn print(_window: &Window, pdf: &[u8], title: &str) -> Result<(), Box> { + let path = crate::print::spooled(pdf, title)?; + let title = title.to_owned(); + std::thread::spawn(move || { + if let Err(error) = portal(&path, &title) { + eprintln!("The print portal failed, opening the PDF instead: {error}"); + crate::platform::reveal(&path); + } + }); + Ok(()) +} + +fn portal(path: &std::path::Path, title: &str) -> Result<(), Box> { + let connection = zbus::blocking::connection::Builder::session()? + .method_timeout(Duration::from_secs(5)) + .build()?; + let portal = zbus::blocking::Proxy::new( + &connection, + "org.freedesktop.portal.Desktop", + "/org/freedesktop/portal/desktop", + "org.freedesktop.portal.Print", + )?; + // A request's path follows from the sender and the token, so its answer can be awaited + // before it is asked for. + let sender = connection + .unique_name() + .ok_or("No D-Bus name")? + .trim_start_matches(':') + .replace('.', "_"); + let request = |token: &str| -> Result<_, Box> { + let path = format!("/org/freedesktop/portal/desktop/request/{sender}/{token}"); + let request = zbus::blocking::Proxy::new( + &connection, + "org.freedesktop.portal.Desktop", + path, + "org.freedesktop.portal.Request", + )?; + Ok(request.receive_signal("Response")?) + }; + let token = format!("snowbound{}", std::process::id()); + let mut answers = request(&token)?; + let options = HashMap::from([("handle_token", Value::from(token.as_str()))]); + let empty: HashMap<&str, Value> = HashMap::new(); + let _: zbus::zvariant::OwnedObjectPath = + portal.call("PreparePrint", &("", title, &empty, &empty, &options))?; + let answer = answers.next().ok_or("The print dialog did not answer")?; + let (response, results): (u32, HashMap) = answer.body().deserialize()?; + // 1 is cancelled. + if response != 0 { + return Ok(()); + } + let prepared = results + .get("token") + .and_then(|token| u32::try_from(token).ok()) + .ok_or("The print dialog gave no token")?; + let file = std::fs::File::open(path)?; + let options = HashMap::from([("token", Value::from(prepared))]); + let _: zbus::zvariant::OwnedObjectPath = + portal.call("Print", &("", title, Fd::from(&file), &options))?; + Ok(()) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn countries_pick_their_paper() { + assert_eq!(paper_of("en_GB.UTF-8"), canvas::print::A4); + assert_eq!(paper_of("es_MX.UTF-8"), canvas::print::LETTER); + assert_eq!(paper_of("C"), canvas::print::LETTER); + } +} diff --git a/crates/snowbound/src/print_macos.rs b/crates/snowbound/src/print_macos.rs new file mode 100644 index 0000000000000000000000000000000000000000..56e88031505bc70ff3576eee13c2daed3d6fad05 --- /dev/null +++ b/crates/snowbound/src/print_macos.rs @@ -0,0 +1,153 @@ +//! Printing on macOS: AppKit's print panel as a sheet on the window, printing the PDF +//! through PDFKit, which fits each sheet to the paper chosen. Mac OS X 10.6's PDFKit +//! cannot print a document, so there the PDF opens in Preview. + +use objc2::{ + msg_send, msg_send_id, + rc::Retained, + runtime::{AnyClass, AnyObject, Bool, Sel}, + sel, +}; +use objc2_foundation::{MainThreadMarker, NSSize, NSString}; +use std::error::Error; +use winit::{ + raw_window_handle::{HasWindowHandle, RawWindowHandle}, + window::Window, +}; + +// PDFKit, inside Quartz on every macOS. +#[link(name = "Quartz", kind = "framework")] +unsafe extern "C" {} + +fn class(name: &str) -> &'static AnyClass { + AnyClass::get(name).expect("AppKit and PDFKit are linked") +} + +/// The paper Page Setup defaults to, in points. +pub fn paper() -> [f32; 2] { + MainThreadMarker::new().expect("Printing belongs to the main thread"); + unsafe { + let info: Retained = msg_send_id![class("NSPrintInfo"), sharedPrintInfo]; + let size: NSSize = msg_send![&info, paperSize]; + if size.width > 0.0 && size.height > 0.0 { + [size.width as f32, size.height as f32] + } else { + canvas::print::LETTER + } + } +} + +/// PDFKit's print operation for `pdf` fitted to `info`'s paper, where PDFKit prints. +fn operation(pdf: &[u8], info: &AnyObject) -> Option> { + unsafe { + let data: Retained = msg_send_id![ + class("NSData"), + dataWithBytes: pdf.as_ptr().cast::(), + length: pdf.len() + ]; + let document: Option> = + msg_send_id![msg_send_id![class("PDFDocument"), alloc], initWithData: &*data]; + let document = document?; + let prints: bool = msg_send![ + &document, + respondsToSelector: sel!(printOperationForPrintInfo:scalingMode:autoRotate:) + ]; + if !prints { + return None; + } + // kPDFPrintPageScaleToFit. + msg_send_id![ + &document, + printOperationForPrintInfo: info, + scalingMode: 1_isize, + autoRotate: Bool::YES + ] + } +} + +/// Shows the print panel for `pdf` as a sheet on `window`. +pub fn print(window: &Window, pdf: &[u8], title: &str) -> Result<(), Box> { + MainThreadMarker::new().expect("Printing belongs to the main thread"); + unsafe { + let shared: Retained = msg_send_id![class("NSPrintInfo"), sharedPrintInfo]; + let info: Retained = msg_send_id![&shared, copy]; + let Some(operation) = operation(pdf, &info) else { + crate::platform::reveal(crate::print::spooled(pdf, title)?); + return Ok(()); + }; + let _: () = msg_send![&operation, setJobTitle: &*NSString::from_str(title)]; + let RawWindowHandle::AppKit(handle) = window.window_handle()?.as_raw() else { + unreachable!("A macOS window is AppKit's") + }; + let view = &*handle.ns_view.as_ptr().cast::(); + let window: Retained = msg_send_id![view, window]; + let _: () = msg_send![ + &operation, + runOperationModalForWindow: &*window, + delegate: std::ptr::null::(), + didRunSelector: None::, + contextInfo: std::ptr::null_mut::() + ]; + } + Ok(()) +} + +#[cfg(test)] +mod tests { + use super::*; + + /// The print operation `print` runs, saving to a file instead of showing the panel. + #[test] + fn pdfkit_prints_the_pages() { + let folder = std::env::temp_dir().join(format!("snowbound-print-{}", std::process::id())); + std::fs::create_dir_all(&folder).unwrap(); + let printed = folder.join("printed.pdf"); + let sheet = draw::Sheet { + size: canvas::print::LETTER, + layers: Vec::new(), + }; + let pdf = draw::pdf( + "Two sheets", + &[ + sheet, + draw::Sheet { + size: canvas::print::LETTER, + layers: Vec::new(), + }, + ], + ) + .unwrap(); + unsafe { + let info: Retained = msg_send_id![class("NSPrintInfo"), new]; + let url: Retained = msg_send_id![ + class("NSURL"), + fileURLWithPath: &*NSString::from_str(printed.to_str().unwrap()) + ]; + let settings: Retained = msg_send_id![&info, dictionary]; + let _: () = msg_send![ + &settings, + setObject: &*url, + forKey: &*NSString::from_str("NSJobSavingURL") + ]; + let _: () = msg_send![&info, setJobDisposition: &*NSString::from_str("NSPrintSaveJob")]; + let operation = operation(&pdf, &info).expect("PDFKit prints documents"); + let _: () = msg_send![&operation, setShowsPrintPanel: false]; + let _: () = msg_send![&operation, setShowsProgressPanel: false]; + let ran: bool = msg_send![&operation, runOperation]; + assert!(ran); + } + let bytes = std::fs::read(&printed).unwrap(); + unsafe { + let data: Retained = msg_send_id![ + class("NSData"), + dataWithBytes: bytes.as_ptr().cast::(), + length: bytes.len() + ]; + let document: Retained = + msg_send_id![msg_send_id![class("PDFDocument"), alloc], initWithData: &*data]; + let pages: usize = msg_send![&document, pageCount]; + assert_eq!(pages, 2); + } + std::fs::remove_dir_all(&folder).unwrap(); + } +} diff --git a/crates/snowbound/src/print_windows.rs b/crates/snowbound/src/print_windows.rs new file mode 100644 index 0000000000000000000000000000000000000000..539dcd52e2bb80fb72d1fb313e6ee585e3a1f992 --- /dev/null +++ b/crates/snowbound/src/print_windows.rs @@ -0,0 +1,61 @@ +//! Printing on Windows: the PDF goes to the shell's print verb for PDFs, whose handler +//! shows the print dialog; where none prints PDFs, it opens in the viewer to print from. + +use std::{error::Error, os::windows::ffi::OsStrExt}; +use windows_sys::Win32::{ + Globalization::{GetLocaleInfoEx, LOCALE_IPAPERSIZE}, + UI::{Shell::ShellExecuteW, WindowsAndMessaging::SW_SHOWNORMAL}, +}; +use winit::{ + raw_window_handle::{HasWindowHandle, RawWindowHandle}, + window::Window, +}; + +fn wide(text: impl AsRef) -> Vec { + text.as_ref().encode_wide().chain([0]).collect() +} + +/// The paper the user's locale prints on: 1 is US Letter, 5 Legal, 9 A4. +pub fn paper() -> [f32; 2] { + let mut value = [0_u16; 4]; + // SAFETY: the buffer's length is passed with it; a null name is the user's locale. + let length = unsafe { + GetLocaleInfoEx( + std::ptr::null(), + LOCALE_IPAPERSIZE, + value.as_mut_ptr(), + value.len() as i32, + ) + }; + let size = String::from_utf16_lossy(&value[..(length.max(1) - 1) as usize]); + match size.as_str() { + "9" => canvas::print::A4, + _ => canvas::print::LETTER, + } +} + +pub fn print(window: &Window, pdf: &[u8], title: &str) -> Result<(), Box> { + let path = crate::print::spooled(pdf, title)?; + let owner = match window.window_handle()?.as_raw() { + RawWindowHandle::Win32(handle) => handle.hwnd.get() as _, + _ => std::ptr::null_mut(), + }; + for verb in ["print", "open"] { + // SAFETY: the strings are NUL-terminated and outlive the call. + let done = unsafe { + ShellExecuteW( + owner, + wide(verb).as_ptr(), + wide(&path).as_ptr(), + std::ptr::null(), + std::ptr::null(), + SW_SHOWNORMAL, + ) + }; + // ShellExecute's success is a pseudo-handle above 32. + if done as isize > 32 { + return Ok(()); + } + } + Err("No application on this computer prints or opens PDFs.".into()) +} diff --git a/crates/snowbound/src/screenshot.rs b/crates/snowbound/src/screenshot.rs index cee28477cea62966a275ae7fcb4a8af09a048fed..2ffe981c7e654bafa0ed303f28460fa817de502a 100644 --- a/crates/snowbound/src/screenshot.rs +++ b/crates/snowbound/src/screenshot.rs @@ -40,8 +40,8 @@ pub(crate) fn prepare() { impl State { /// Writes `PREFIX-light.png` and `PREFIX-dark.png`, the page unfocused so no caret shows; - /// as a Snow Leopard window, `PREFIX-snow-leopard.png` and, not key, - /// `PREFIX-snow-leopard-other.png`, at 10.6's one pixel per point. + /// as a Snow Leopard window, at 10.6's one pixel per point, also `PREFIX-light-other.png` + /// and `PREFIX-dark-other.png` as the window looks when not key. pub(crate) fn screenshot(&mut self, prefix: &Path) -> Result<(), Box> { let size = match std::env::var("SNOWBOUND_SCREENSHOT_SIZE") { Ok(size) => size diff --git a/crates/snowbound/src/screenshot/snow_leopard.rs b/crates/snowbound/src/screenshot/snow_leopard.rs index 25783b21afbbcd77ce30587087e429e6ec84627a..d6d9595a44ed811a4caa2288bdc964f822a16828 100644 --- a/crates/snowbound/src/screenshot/snow_leopard.rs +++ b/crates/snowbound/src/screenshot/snow_leopard.rs @@ -30,21 +30,23 @@ pub(super) fn screenshot( size: [f32; 2], ) -> Result<(), Box> { let title = state.window.title(); - for (name, key) in [("snow-leopard", true), ("snow-leopard-other", false)] { - state.window.set_theme(Some(Appearance::Light)); - state.set_appearance(Appearance::Light); - // Over the textured window's gradient, as `install_backdrop` leaves it on 10.6. - state.ui.theme = theme(Appearance::Light, state.light_pages, true); - state.titlebar = [state.ui.theme.strip; 2]; - state.ui.window_focused = key; - state.settle_frame(size, 1.0)?; - let content = state.capture()?; - let bar = title_bar(state, &title, size[0], key)?; - let [width, height] = [size[0] as usize, size[1] as usize]; - let window = window(&content, &bar, [width, height], key)?; - let (canvas, shadowed) = shadow(&window, [width, height + TITLE_LINE], key); - let path = PathBuf::from(format!("{}-{name}.png", prefix.display())); - write_png(&path, canvas.map(|side| side as u32), &shadowed)?; + for (name, appearance) in [("light", Appearance::Light), ("dark", Appearance::Dark)] { + for (suffix, key) in [("", true), ("-other", false)] { + state.window.set_theme(Some(appearance)); + state.set_appearance(appearance); + // Over the textured window's gradient, as `install_backdrop` leaves it on 10.6. + state.ui.theme = theme(appearance, state.light_pages, true); + state.titlebar = [state.ui.theme.strip; 2]; + state.ui.window_focused = key; + state.settle_frame(size, 1.0)?; + let content = state.capture()?; + let bar = title_bar(state, &title, size[0], key)?; + let [width, height] = [size[0] as usize, size[1] as usize]; + let window = window(&content, &bar, [width, height], key)?; + let (canvas, shadowed) = shadow(&window, [width, height + TITLE_LINE], key); + let path = PathBuf::from(format!("{}-{name}{suffix}.png", prefix.display())); + write_png(&path, canvas.map(|side| side as u32), &shadowed)?; + } } Ok(()) } diff --git a/crates/snowbound/src/settings.rs b/crates/snowbound/src/settings.rs index 7b96095c7844d128949faaa962f0911f8836c18a..2e08625bb54e4a5c5e81676f4b0efddb4ef439be 100644 --- a/crates/snowbound/src/settings.rs +++ b/crates/snowbound/src/settings.rs @@ -20,7 +20,7 @@ pub struct Settings { /// first saved. pub user_name: Option, pub color_scheme: ColorScheme, - /// Keeps pages white in the Dark color scheme. + /// Keeps pages white in a dark appearance: Pages Match UI Theme off. pub light_pages: bool, /// Leaves misspelled words unmarked, as OneNote's Hide Spelling Errors. pub hide_spelling: bool, @@ -33,6 +33,35 @@ pub struct Settings { /// Draws a tablet pen's strokes at its width, as OneNote 2010 with "Use pen pressure /// sensitivity" off. pub ignore_pen_pressure: bool, + /// Places and moves things where they are dropped, as OneNote's Snap To Grid off. + pub ignore_grid: bool, + /// Options' Default font: new text's font and size, and new titles' font. + pub default_font: DefaultFont, + /// OneNote's "Page tabs appear on the left". + pub page_tabs_left: bool, + /// OneNote's "Navigation bar appears on the left" turned off: the notebooks on the right. + pub navigation_bar_right: bool, + /// Servers Open Notebook from Server signed in to, latest first, as addresses without a + /// password. + pub servers: Vec, +} + +/// The font and size OneNote's Default font gives new text. +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +#[serde(default)] +pub struct DefaultFont { + pub face: String, + pub size: f32, +} + +impl Default for DefaultFont { + /// OneNote 2010's: Calibri 11. + fn default() -> Self { + Self { + face: "Calibri".into(), + size: 11.0, + } + } } /// What the toolbar's buttons apply from their menus' last picks. @@ -144,6 +173,11 @@ impl crate::State { tags: (self.tags != canvas::editor::NoteTag::defaults()).then(|| self.tags.clone()), manual_updates: !self.updates.automatic(), ignore_pen_pressure: !self.pen_pressure, + ignore_grid: !self.view.snap_to_grid, + default_font: self.default_font.clone(), + page_tabs_left: self.page_tabs_left, + navigation_bar_right: self.navigation_bar_right, + servers: self.servers.clone(), }; if let Err(error) = settings.save(path) { eprintln!("Cannot save the settings in {}: {error}", path.display()); @@ -204,6 +238,14 @@ mod tests { }]), manual_updates: true, ignore_pen_pressure: true, + ignore_grid: true, + default_font: DefaultFont { + face: "Georgia".into(), + size: 14.0, + }, + page_tabs_left: true, + navigation_bar_right: true, + servers: vec!["smb://clover@nas/Notes".into()], }; settings.save(&path).unwrap(); assert_eq!(Settings::load(&path), settings); diff --git a/crates/snowbound/src/sidebar.rs b/crates/snowbound/src/sidebar.rs index 10584d7bf1a77f1b80533ff7a793f0120e7c1a60..55ec410bbed04f9839ce9fe59234368d905822b8 100644 --- a/crates/snowbound/src/sidebar.rs +++ b/crates/snowbound/src/sidebar.rs @@ -1074,7 +1074,7 @@ impl crate::State { } /// The window below the title bar on the first run, or once every notebook is closed: - /// what is missing, and the two ways to start. + /// what is missing, and the ways to start. pub(crate) fn welcome(&mut self, theme: &Theme) { let id = self.ui.id("welcome"); #[cfg(target_os = "linux")] @@ -1121,6 +1121,12 @@ impl crate::State { crate::Command::OpenFromServer(None), ), ]) + .chain(crate::guide::OFFERED.then_some(( + "guide", + art::PAGE, + "Open the Snowbound Guide", + crate::Command::OpenGuide, + ))) .chain(install) .collect(), ); diff --git a/crates/snowbound/src/update.rs b/crates/snowbound/src/update.rs index fceaa6392ebef81163c99268a14be316167653ed..36a056908bfa734a0ab008b825b66dffd7d371c4 100644 --- a/crates/snowbound/src/update.rs +++ b/crates/snowbound/src/update.rs @@ -31,15 +31,39 @@ fn running() -> Option { Version::parse(option_env!("SNOWBOUND_BUILD")?) } -/// This build's platform, as `latest.json` and `build.json` key their entries. +/// This build's platform, as `latest.json` and `build.json` key their entries; Apple +/// silicon's for an Intel build Rosetta runs. fn platform() -> String { - if cfg!(target_os = "macos") && !cfg!(feature = "wgpu") { + if translated() { + "macos-aarch64".to_owned() + } else if cfg!(target_os = "macos") && !cfg!(feature = "wgpu") { "macos-10.6".to_owned() } else { format!("{}-{}", std::env::consts::OS, std::env::consts::ARCH) } } +#[cfg(all(target_os = "macos", target_arch = "x86_64"))] +fn translated() -> bool { + let mut translated: libc::c_int = 0; + let mut size = std::mem::size_of_val(&translated); + let found = unsafe { + libc::sysctlbyname( + c"sysctl.proc_translated".as_ptr(), + (&raw mut translated).cast(), + &mut size, + std::ptr::null_mut(), + 0, + ) + }; + found == 0 && translated == 1 +} + +#[cfg(not(all(target_os = "macos", target_arch = "x86_64")))] +fn translated() -> bool { + false +} + /// A published build: the day of its commit on `main`, in Los Angeles, and how many of that /// day's commits on `main` lead up to and include it. `2026-09-29-r10` names it in manifests. #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] @@ -302,6 +326,8 @@ fn check( progress: &dyn Fn(Status), ) -> Status { let platform = platform(); + // Under Rosetta the native build of the same version is still the update. + let running = running.filter(|_| !translated()); let fetch = |path: &str, limit| { get(path, limit).map_err(|error| { eprintln!("Cannot fetch {BASE}{path}: {error}"); diff --git a/crates/snowbound/src/windows.rs b/crates/snowbound/src/windows.rs index d5ea3965edb7bd32ff1ed0018289df6645702a47..ab1718368c00f50fc259b4de77f309d3271cb0e2 100644 --- a/crates/snowbound/src/windows.rs +++ b/crates/snowbound/src/windows.rs @@ -175,6 +175,9 @@ pub fn window_attributes() -> WindowAttributes { .with_taskbar_icon(icon(32).ok()) .with_decorations(caption() != Caption::Drawn) .with_undecorated_shadow(true) + // What GDI paints under the material would show through the row; every 10 draws + // with Direct3D 12, which needs no such bitmap. + .with_no_redirection_bitmap(caption() == Caption::Drawn && version().0 >= 10) } /// Takes the window's frame messages ahead of winit's: over glass or Mica, the caption @@ -236,9 +239,6 @@ unsafe extern "system" fn frame_procedure( wm::WM_SETTINGCHANGE | wm::WM_DWMCOLORIZATIONCOLORCHANGED => { if message == wm::WM_SETTINGCHANGE && setting(lparam) == "ImmersiveColorSet" { refresh_color_policy(); - if ACRYLIC.load(Ordering::Relaxed) { - accent(hwnd, Accent::Acrylic); - } } if let Some(proxy) = QUIT.get() { let _ = proxy.send_event(crate::UserEvent::Appearance); @@ -445,6 +445,26 @@ pub fn cuts_corners() -> bool { /// Whether Windows 10 shows acrylic under the window, which a drag swaps for plain blur. static ACRYLIC: AtomicBool = AtomicBool::new(false); +/// Whether the app's appearance is dark, which Options can set apart from the system's. +static DARK: AtomicBool = AtomicBool::new(false); + +/// Holds the frame, its caption buttons and its material to the app's `appearance`. +pub fn follow_appearance(window: &Window, appearance: Theme) { + let dark = appearance == Theme::Dark; + DARK.store(dark, Ordering::Relaxed); + let (major, _, build) = version(); + if major < 10 { + return; + } + let hwnd = hwnd(window); + // DWMWA_USE_IMMERSIVE_DARK_MODE, 19 before build 18985. + let attribute = if build >= 18985 { 20 } else { 19 }; + set_attribute(hwnd, attribute, &BOOL::from(dark)); + if ACRYLIC.load(Ordering::Relaxed) { + accent(hwnd, Accent::Acrylic); + } +} + enum Accent { Blur, /// Acrylic in the shell's own tints: Windows 10's light and dark flyouts. @@ -482,8 +502,8 @@ fn accent(hwnd: HWND, accent: Accent) -> bool { Accent::Acrylic => Policy { state: 4, flags: 2, - // 0xAABBGGRR, after the apps' colour mode. - tint: if registry_dword(PERSONALIZE, "AppsUseLightTheme") == Some(0) { + // 0xAABBGGRR, after the app's appearance. + tint: if DARK.load(Ordering::Relaxed) { 0xcc20_2020 } else { 0xccf3_f3f3 @@ -577,7 +597,7 @@ pub fn titlebar(appearance: Theme) -> Option<[[f32; 4]; 2]> { /// The theme over the window's material. Over Windows 7's glass, fields and tool buttons /// take white faces, as Internet Explorer's do there, so their text and icons stay legible, /// and the sidebar stays opaque. -pub fn over_backdrop(theme: ui::Theme) -> ui::Theme { +pub fn over_backdrop(theme: ui::Theme, _: Theme) -> ui::Theme { let sidebar = theme.sidebar; let theme = theme.over_backdrop(); if caption() != Caption::Glass || eleven() { @@ -795,6 +815,15 @@ impl Clipboard { pub fn get_text(&mut self) -> Result { self.0.get_text() } + + pub fn get_files(&mut self) -> Vec { + self.0.get().file_list().unwrap_or_default() + } + + /// The clipboard's PNG, or else its device-independent bitmap. + pub fn get_picture(&mut self) -> Option> { + crate::paste::bitmap(self.0.get_image().ok()?) + } } /// The DWORD `value` under `key` in the user's registry hive. @@ -884,6 +913,32 @@ pub fn settings_dir() -> Option { Some(PathBuf::from(std::env::var_os("APPDATA")?).join("Snowbound")) } +/// The user's Documents known folder, wherever it was moved. +pub fn documents_dir() -> Option { + use std::os::windows::ffi::OsStringExt; + use windows_sys::Win32::{ + System::Com::CoTaskMemFree, + UI::Shell::{FOLDERID_Documents, KF_FLAG_DEFAULT, SHGetKnownFolderPath}, + }; + let mut path = std::ptr::null_mut(); + let found = unsafe { + SHGetKnownFolderPath( + &FOLDERID_Documents, + KF_FLAG_DEFAULT as u32, + std::ptr::null_mut(), + &mut path, + ) + } == 0; + let folder = found.then(|| unsafe { + let length = (0..).take_while(|&at| *path.add(at) != 0).count(); + PathBuf::from(std::ffi::OsString::from_wide(std::slice::from_raw_parts( + path, length, + ))) + }); + unsafe { CoTaskMemFree(path as _) }; + folder +} + /// None: Windows reaches a share by its UNC path with the share modes and byte-range /// locks OneNote takes, so a notebook there opens as a folder, as OneNote opens it. /// Snowbound's own client serves Open Notebook from Server…. diff --git a/crates/ui/src/layout.rs b/crates/ui/src/layout.rs index c1aa77ebd8ad56b68022d766b1d61818628d0ded..4ecaac97da187948705fc7723765b022d04e04e9 100644 --- a/crates/ui/src/layout.rs +++ b/crates/ui/src/layout.rs @@ -265,6 +265,40 @@ fn flow(nodes: &[Built], index: usize, axis: usize) -> f32 { } } +/// The least width `index`'s children fit in, with its padding: each row's groups folded, and +/// each box sized on its own yielding all its strictness lets it. +pub(crate) fn narrowest(nodes: &[Built], index: usize) -> f32 { + let node = &nodes[index]; + let sizes = node + .children + .iter() + .filter(|child| { + !nodes[**child].flags.contains(Flags::FLOAT) && nodes[**child].anchor.is_none() + }) + .map(|child| least(nodes, *child)); + let content = if along(node, 0) { + let (sum, count) = sizes.fold((0.0, 0), |(sum, count), size| (sum + size, count + 1)); + sum + node.gap * (count.max(1) - 1) as f32 + } else { + sizes.fold(0.0, f32::max) + }; + content + 2.0 * node.pad[0] +} + +/// The least width `index` takes without clipping its children. +fn least(nodes: &[Built], index: usize) -> f32 { + let node = &nodes[index]; + if node.fold.is_some() { + return least(nodes, node.children[1]) + 2.0 * node.pad[0]; + } + let own = match node.size[0].size { + Size::Pixels(pixels) => pixels, + Size::Text => node.content_width() + 2.0 * node.pad[0], + Size::Fraction(_) | Size::Children => return narrowest(nodes, index), + }; + own * node.size[0].strictness.clamp(0.0, 1.0) +} + fn fit_labels(nodes: &mut [Built], texts: &mut Texts, frame: u64) { for node in nodes.iter_mut() { let Some(label) = node.label.clone() else { diff --git a/crates/ui/src/lib.rs b/crates/ui/src/lib.rs index 7587f2a7a17a9e2af37eb2c790c79fa0788bf5c6..1395106f7de45167b5738ab99de16ecf81fb149e 100644 --- a/crates/ui/src/lib.rs +++ b/crates/ui/src/lib.rs @@ -827,6 +827,13 @@ impl Ui { self.hit(point, Flags::CLICKABLE | Flags::CUSTOM) } + /// The least width the box's children fit in, with its padding, as built this frame or + /// last: each row's groups folded, and each box yielding all its strictness lets it. + pub fn narrowest(&self, id: Id) -> Option { + let index = self.nodes.iter().position(|node| node.id == id)?; + Some(layout::narrowest(&self.nodes, index)) + } + /// The box's rectangle from the latest layout. pub fn rect(&self, id: Id) -> Option<[f32; 4]> { self.states.get(&id).map(|state| state.rect) diff --git a/crates/ui/src/tests.rs b/crates/ui/src/tests.rs index c3328d75b795b481c6c9b2dd63268a0713f1e7d0..10702a332fe96faa17abb25aff2a3e0675ed01ea 100644 --- a/crates/ui/src/tests.rs +++ b/crates/ui/src/tests.rs @@ -216,6 +216,17 @@ fn a_row_squeezes_its_boxes_only_once_every_group_is_folded() { assert_eq!(rects[4], Some([80.0, 0.0, 100.0, 20.0])); } +#[test] +fn a_row_is_narrowest_with_every_group_folded_and_every_box_squeezed() { + let mut ui = Ui::new(Theme::dark(), DOUBLE_CLICK); + folding_row(&mut ui, 300.0, &[0, 1]); + let row = Id::ROOT.child("row"); + // The space gives all, the loose box 60 of 80, each group 80 of 100. + assert_eq!(ui.narrowest(row), Some(60.0)); + let rects = folding_row(&mut ui, 60.0, &[0, 1]); + assert_eq!(rects[4], Some([40.0, 0.0, 60.0, 20.0])); +} + #[test] fn a_box_sized_by_its_children_yields_what_they_yield() { let mut ui = Ui::new(Theme::dark(), DOUBLE_CLICK); diff --git a/crates/ui/src/text.rs b/crates/ui/src/text.rs index 5b31bdec53e6c39a1227e233bc4fd9a4fd44b9ce..d091cd818971b224f8cac8c9e5c58a32c9adbc24 100644 --- a/crates/ui/src/text.rs +++ b/crates/ui/src/text.rs @@ -149,6 +149,7 @@ impl Glyphs for Label { if let PositionedLayoutItem::GlyphRun(run) = item { draw::paint_parley_run( &run, + "", metrics.baseline, 0.0, [metrics.block_min_coord, metrics.line_height], diff --git a/docs/guide-notebook/Snowbound Guide/.snowbound/tags.json b/docs/guide-notebook/Snowbound Guide/.snowbound/tags.json new file mode 100644 index 0000000000000000000000000000000000000000..ecba716aef0706fcca587394ef348cde0185ccbd --- /dev/null +++ b/docs/guide-notebook/Snowbound Guide/.snowbound/tags.json @@ -0,0 +1,8 @@ +[ + { + "name": "Snowflake", + "shape": 34, + "art": "308029094b76e765ca4025c6e8978ff3f1e5f696601ca46fed3803a81c37792c.svg", + "mapped": 134352774263488320 + } +] \ No newline at end of file diff --git a/docs/guide-notebook/Snowbound Guide/.snowbound/tags/308029094b76e765ca4025c6e8978ff3f1e5f696601ca46fed3803a81c37792c.svg b/docs/guide-notebook/Snowbound Guide/.snowbound/tags/308029094b76e765ca4025c6e8978ff3f1e5f696601ca46fed3803a81c37792c.svg new file mode 100644 index 0000000000000000000000000000000000000000..053c11e5abb0890352658594633d2dc5f66e0c39 --- /dev/null +++ b/docs/guide-notebook/Snowbound Guide/.snowbound/tags/308029094b76e765ca4025c6e8978ff3f1e5f696601ca46fed3803a81c37792c.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/docs/guide-notebook/Snowbound Guide/Drawing & Recording.one b/docs/guide-notebook/Snowbound Guide/Drawing & Recording.one new file mode 100644 index 0000000000000000000000000000000000000000..4dea2f9759ef2455094ff9466c7cc7344f7497f6 GIT binary patch literal 92072 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

2P?14PS4cK4^zi*kE->3uGfYk2|iFV7f(vD{2wc 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 literal 0 HcmV?d00001 diff --git a/docs/guide-notebook/Snowbound Guide/Open Notebook.onetoc2 b/docs/guide-notebook/Snowbound Guide/Open Notebook.onetoc2 new file mode 100644 index 0000000000000000000000000000000000000000..6da28a3a19cf28a297736704ea4fc74672bf1be7 GIT binary patch literal 6008 zcmeHLe@s<%6h9Cok%MP|AUqtF(`R!?VCobKK}CU(L~yc*$B+qQAt?cBwOi@L!Qwr! zfw>_$e{NuyFH0+AYJ)~jimlXWI`t2K1Sa)NHx`}Gz2EzOUNY8JfB4S!z4xB;{eI8= zen01&&;7pl(X5f=i+3v1o3H9_t$MmL-|Jjk{6<}4MoVX9P=cXvF1g5yKYyr;Fk6@H z?+rB%bRW48!TpX+9X`T>XFt^-?yB9zY*P=veyiH1@Po-$(Pr{3Mm!r8lkHj^YI~F) zZX0r6F$aITv|cy+{JM(Uchoh^Ik|05Lg2WCTP;_w??1ief%7bn=0V_*L_qSQdwQCx z?EUQTe^`%h%GozTKoML{(x#58Goix+Nnh+uPWdgbeZ))jMcg3idURIavh4EoeU{Qw z&&K;7R{KUnQt6)(OcG5s@`c6Ky+KD(bT!qGkK#nfH-B!*R9sibkfd7lJbHv1o4cRj z3rh>Pw3Bh~o(VZ!tM2D1bg+!)m%6?XE_I1y(uo)L$|H%uRS>AI{({69KNFd*hz$~zVB&i;Wr_zLUw=7#s+jx{z-$~#nyeM7`M6~%M)AmBmZ5kWxmmif9vPr=x+ z`Q#D4syqk&09SyU$4pa)H@bD&QY`jdl(Sm=>LZ=IYI4t<)?v*!8sLXQ#p+}ivO z=nI6NkefLJdWz5+_TI_iM~`?A@F4I%A>eqn`G-r8d}wDR=}$1PmGT|@hNGV){#@kU zDPQ`o(`d#=l_ts#xc`$Lw?y9gi^ABzI z#+etxT#t$BnYRWU$ztTDo^Tb%VBH&{HwwM%2A-} z6*8V>w3dKx1r^YGz829MH*6ihJCE^f;MTvY+OnglVbSq8{rt6-n(wegEiBnA3;O>B zZb0UW_~aPbk=yr3!pDK-S8fl-WoVafc5=YY^lcN~>Mx1^EEU-h%WV~7P~w2gG{$BL zXWDvtjq$M~=A3;zTSBO?D0}X~r~7vsM|$8F-v9lP?#^9{EVVb2@6M9afR7fYY?eg> zzopj3o{~#L8O^>!M_1HcoTlcTRz6}eqvhj$ky6Dx#yua60@x_@vKuS}P2}T!@uSO+ zZ4bx2tE~Qle??bXL+Irz*0awCA)8R=D;eFjw1J}dJfKuNvayhg-Exr!6VI~YjV0MJ zhd=Fl$KOi8{c550+V=XHiw}gB)+L+IcVH`8v0$?-=y%E6vEp8pXF2%6m;2IBy_EQ; zx4vO9;)I2c7LRfPsgcL1h%1<*3VKB^%GjUXV1Z~N9wzy`NEF33H6EOEPI&pV!HyX+ z(uSF&&CkzR3U>d{)VBQC%Y!W;nI|S;P7Jq29Hjzg=n`gS@Cc%}Lgs4J%o<^Lt`=t= zew@7^F54$;c;UeGuGG32!#>l4+BRcLTCrlYEa?A_;(~Z#!yWI1zq+I6T2jNLuy5N8 zTVuiJh=_7TCvuGl{@*Z&aLBdAPLyTis`5Dw$Sm{NrpAlaQR2{=-FIx|!37!Sy*U$q z(tUCnS&b8P7FP-?#xV|Aw2`Ays8K;Y%bpLMLjG)Ut|R!h<%H9Ba~$^|UV+CG27j3zdOcSM`e@m?X0@gv3$#q_lFXSJKs?2NUOdOFW36Q lcx+57j)+xzh_X~8-`wj?Cjy1EM*(3&Xd;e|XCXC?e*r*xI!FKj literal 0 HcmV?d00001 diff --git a/docs/guide-notebook/Snowbound Guide/Sharing & Sync.one b/docs/guide-notebook/Snowbound Guide/Sharing & Sync.one new file mode 100644 index 0000000000000000000000000000000000000000..852a9c422a1a640013f623473e563c6d441e9ef0 GIT binary patch literal 26976 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 literal 0 HcmV?d00001 diff --git a/docs/guide-notebook/Snowbound Guide/Tags & Search.one b/docs/guide-notebook/Snowbound Guide/Tags & Search.one new file mode 100644 index 0000000000000000000000000000000000000000..63da6190cabe3472019bafc8fb0bb8d7e5c197e6 GIT binary patch literal 35864 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 literal 0 HcmV?d00001 diff --git a/docs/guide-notebook/Snowbound Guide/Writing & Formatting.one b/docs/guide-notebook/Snowbound Guide/Writing & Formatting.one new file mode 100644 index 0000000000000000000000000000000000000000..0acefb94af0fe9b143da7db292bbe327c84064c0 GIT binary patch literal 86896 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 z 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

e`E;D!S`Lc^og#xGKq-Z5M0$WBm;8=1S@* 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 Qe-!xtI0Zho0q9o#ADS)IE&u=k literal 0 HcmV?d00001 diff --git a/platform/snow-leopard/rt/appkit.c b/platform/snow-leopard/rt/appkit.c index 9df6250f0beb2decec8f1fe00eb0bc9b54dfa25a..8022bbfd3a837b865e755c75103f6569e035189d 100644 --- a/platform/snow-leopard/rt/appkit.c +++ b/platform/snow-leopard/rt/appkit.c @@ -127,11 +127,6 @@ static CGFloat red(id self, SEL _cmd) { return component(self, 0); } static CGFloat green(id self, SEL _cmd) { return component(self, 1); } static CGFloat blue(id self, SEL _cmd) { return component(self, 2); } -static id black(id self, SEL _cmd) { return SEND(objc_getClass("NSColor"), "blackColor"); } -static id secondary_selection(id self, SEL _cmd) { - return SEND(objc_getClass("NSColor"), "secondarySelectedControlColor"); -} - #define RECT "{CGRect={CGPoint=dd}{CGSize=dd}}" static void add(const char *class_name, int meta, const char *selector, void *imp, const char *types) { @@ -153,7 +148,6 @@ __attribute__((constructor)) static void polyfill(void) { add("NSWindow", 0, "setTitlebarAppearsTransparent:", ignore, "v@:c"); add("NSView", 0, "setWantsBestResolutionOpenGLSurface:", ignore, "v@:c"); add("NSView", 0, "setAccessibilityLabel:", set_accessibility_label, "v@:@"); - add("NSDatePicker", 0, "setPresentsCalendarOverlay:", ignore, "v@:c"); add("NSEvent", 0, "hasPreciseScrollingDeltas", no, "c@:"); add("NSEvent", 0, "scrollingDeltaX", delta_x, "d@:"); add("NSEvent", 0, "scrollingDeltaY", delta_y, "d@:"); @@ -163,8 +157,6 @@ __attribute__((constructor)) static void polyfill(void) { add("NSColorSpaceColor", 0, "greenComponent", green, "d@:"); add("NSColorSpaceColor", 0, "blueComponent", blue, "d@:"); add("NSColor", 1, "colorWithSRGBRed:green:blue:alpha:", srgb_color, "@@:dddd"); - add("NSColor", 1, "textInsertionPointColor", black, "@@:"); - add("NSColor", 1, "unemphasizedSelectedTextBackgroundColor", secondary_selection, "@@:"); // One appearance, Aqua, which windows have and nothing changes. appearance_class = (id)objc_getClass("NSAppearance"); diff --git a/tools/RELEASE.md b/tools/RELEASE.md index f4fd2a1639ee71eca6b9ea24be493f0a2d1c881b..f810c5ecd1cd549a94bf9bfa7b240b6c815b03bd 100644 --- a/tools/RELEASE.md +++ b/tools/RELEASE.md @@ -18,16 +18,17 @@ development builds, which never update themselves. ## The published folder ```text -latest.json {"macos-aarch64": "2026-09-29-r10", "macos-10.6": ..., "linux-x86_64": ..., "windows-x86_64": ..., ...} +latest.json {"macos-aarch64": "2026-09-29-r10", "macos-x86_64": ..., "macos-10.6": ..., "linux-x86_64": ..., ...} 2026-09-29.r10/ build.json version, commit, and per platform: file, size, sha256, signature build.json.sig ed25519 signature of build.json, hex Snowbound-2026-09-29-r10-macos-aarch64.zip + Snowbound-2026-09-29-r10-macos-x86_64.zip Snowbound-2026-09-29-r10-macos-10.6.zip snowbound-2026-09-29-r10-linux-x86_64 the executable itself snowbound-2026-09-29-r10-linux-aarch64 - snowbound-2026-09-29-r10-windows-x86_64.exe Windows 7 SP1 to 11 - snowbound-2026-09-29-r10-windows-aarch64.exe Windows 11 on Arm + snowbound-2026-09-29-r10-windows-x86_64.exe + snowbound-2026-09-29-r10-windows-aarch64.exe ``` A build folder is written once, under a hidden `.2026-09-29.r10.partial` name renamed into @@ -82,7 +83,7 @@ quarantine and open directly. ## Publishing ```sh -python3 tools/release.py # all six platforms +python3 tools/release.py # all seven platforms python3 tools/release.py --ad-hoc # the macOS app without Developer ID python3 tools/release.py --dry-run # the same into a new temporary folder python3 tools/release.py --platforms macos-aarch64 linux-x86_64 @@ -99,9 +100,30 @@ publishes as above. Run again for the same commit, it only brings `latest.json` up to date; a different commit that derives the same version is refused. The 10.6 build needs the SDK and nightly toolchain `platform/snow-leopard/cargo.sh` names; the Linux builds need `zig`, as the -cross linker against glibc 2.31; the Windows builds need llvm-mingw, which +cross linker against glibc 2.17; the Windows builds need llvm-mingw, which `platform/windows/toolchain.sh` fetches, and nightly with `rust-src` for -x86_64. All six build from an Apple silicon Mac. +x86_64. All seven build from an Apple silicon Mac. + +## Minimum systems + +Each build runs as far back as its dependencies allow, and newer calls are +checked at run time (`respondsToSelector:`, `available!`, `dlsym`). + +| Platform | Oldest system | Set by | +| --- | --- | --- | +| `macos-aarch64` | macOS 11 | Apple silicon's first; rustc's default | +| `macos-x86_64` | macOS 10.13 | wgpu's Metal floor; `MACOSX_DEPLOYMENT_TARGET` | +| `macos-10.6` | Mac OS X 10.6 | its own SDK, runtime shims and OpenGL renderer | +| `linux-*` | glibc 2.17 (RHEL 7, Debian 8, Ubuntu 14.04) | Rust's floor; zig's glibc target | +| `windows-x86_64` | Windows 7 SP1 | nightly's `x86_64-win7-windows-gnu` | +| `windows-aarch64` | Windows 11 on Arm | `aarch64-pc-windows-gnullvm` | + +`build_macos.py` writes the minimum as `LSMinimumSystemVersion`; the binary +carries it as `LC_BUILD_VERSION` `minos` (`LC_VERSION_MIN_MACOSX` below 10.14), +which `otool -l` shows. `objdump -T` of a Linux executable names no `GLIBC_` +version above 2.17. The Linux executable links only libc, libm, libpthread and +libdl; Wayland, X11, xkbcommon, EGL, Vulkan, fontconfig, GStreamer and Enchant +are loaded at run time. ## In the app @@ -111,7 +133,8 @@ Work Offline is on; Check for Updates… (the app menu on macOS, the command palette elsewhere) checks at once and reports what it found. A check reads `latest.json`, then the named build's `build.json` and signature, and downloads the archive for this platform, verifying size, SHA-256 and -signature. It stages the update beside the install, so the swap is a rename: +signature. An Intel build that Rosetta runs takes `macos-aarch64`'s, even at +its own version. It stages the update beside the install, so the swap is a rename: the app unpacked into `.Snowbound.app.update` next to the bundle on macOS, the executable into `.snowbound.update` next to it on Linux (`.snowbound.exe.update` on Windows). The sync status icon gets a dot, and its popup offers diff --git a/tools/canvas/README.md b/tools/canvas/README.md index e1fabbec57a201a96f3880df9e060057ce498eba..12aa3f7c00c2d6364424146fc23f5ad7c99c70c8 100644 --- a/tools/canvas/README.md +++ b/tools/canvas/README.md @@ -54,7 +54,7 @@ Launched without a file, the app reopens the notebooks open when it last closed, The `ui` crate builds every frame from the application's state. A cache keyed by stable box ids keeps hover, press, focus, scroll and animation values, and the previous frame's layout routes the frame's input before building, so a frame answers input one layout late and paints with its own. Sizes are solved per axis after building: fixed, label-sized, a fraction of an ancestor, or the sum of children, with overflow shared out by each box's strictness. The page is a custom box: `ui` routes it the pointer, wheel, key and input-method events that land on it, in order, and the host hands them to `PageView` and paints the page in a clipped layer of the same frame. Page scrollbars are `ui` widgets over that box; the canvas reports only its scroll bounds. Text fields edit through `draw::edit`, as the page does, so keys, clicks and drags select and move the same way in both. Work the frame asks for (page requests, saving) runs after the frame is painted and requests the frame that shows it. Opening a section or page reads and lays it out on a thread of its own while the current page stays live; the newest replaces the page once the pictures it shows first are drawn, or after 200 ms. -A covered window receives no redraws, so interaction can be scripted: `SNOWBOUND_REPLAY` names a file of `move X Y`, `press [right]`, `release [right]`, `wheel DX DY`, `key NAME`, `type TEXT`, `modifiers [shift] [command]`, `wait MS`, `snapshot PNG_PATH`, `accessibility TEXT_PATH` (the window's accessibility tree, a node a line, as the platform shows it), `appearance light|dark`, `resize WIDTH HEIGHT` and `quit` lines in logical pixels, and each step and every 16 ms of a wait draws a frame. With `--screenshot` as well, the window stays hidden and only the replay's snapshots capture it. Snapshots wait for the page's pictures, file icons and background art to finish rasterizing; `SNOWBOUND_FRAMES` frames never wait, so art appears in the first frame drawn after it is ready. Snapshots omit the window's traffic lights, which AppKit draws. Replays edit and save like a user, so point them at a copy of a notebook. Their edits carry the settings' user name, so give fixture runs a `--settings` file holding `{"user_name": "Snowbound Test"}`. +A covered window receives no redraws, so interaction can be scripted: `SNOWBOUND_REPLAY` names a file of `move X Y`, `press [right]`, `release [right]`, `wheel DX DY`, `pinch FACTOR`, `key NAME`, `type TEXT`, `modifiers [shift] [command]`, `wait MS`, `snapshot PNG_PATH`, `accessibility TEXT_PATH` (the window's accessibility tree, a node a line, as the platform shows it), `appearance light|dark`, `resize WIDTH HEIGHT` and `quit` lines in logical pixels, and each step and every 16 ms of a wait draws a frame. With `--screenshot` as well, the window stays hidden and only the replay's snapshots capture it. Snapshots wait for the page's pictures, file icons and background art to finish rasterizing; `SNOWBOUND_FRAMES` frames never wait, so art appears in the first frame drawn after it is ready. Snapshots omit the window's traffic lights, which AppKit draws. Replays edit and save like a user, so point them at a copy of a notebook. Their edits carry the settings' user name, so give fixture runs a `--settings` file holding `{"user_name": "Snowbound Test"}`. ```sh cp -RL SOURCE_NOTEBOOK /tmp/notebook-copy && chmod u+w /tmp/notebook-copy/*.one diff --git a/tools/canvas/build_macos.py b/tools/canvas/build_macos.py index c5a929946d4634ecfb0c96206144f9be46157839..bd6d6b01478eafddf7f4fbde5be3e12536a43f68 100644 --- a/tools/canvas/build_macos.py +++ b/tools/canvas/build_macos.py @@ -16,6 +16,8 @@ parser = argparse.ArgumentParser(description=__doc__) parser.add_argument('--release', action='store_true') parser.add_argument('--output', type=Path, help='Create a separate bundle at a new .app path') parser.add_argument('--bundle-id', help="Bundle identifier for the separate app; the app's own otherwise") +host = 'aarch64' if platform.machine() == 'arm64' else 'x86_64' +parser.add_argument('--arch', choices=['aarch64', 'x86_64'], default=host, help="The app's architecture; this Mac's by default") parser.add_argument('--snow-leopard', action='store_true', help='Build with platform/snow-leopard/cargo.sh into target/snow-leopard') parser.add_argument('--sign-identity', metavar='SHA1', @@ -29,6 +31,9 @@ if args.bundle_id and not args.output: parser.error('Use --bundle-id with --output.') if args.sign and args.snow_leopard: parser.error('The 10.6 bundle stays unsigned.') +# The oldest macOS each build runs on: 10.6's own build, wgpu's floor on Intel, and Apple +# silicon's first, which rustc also defaults to. +minimum = '10.6' if args.snow_leopard else {'x86_64': '10.13', 'aarch64': '11.0'}[args.arch] if args.output and (args.output.suffix != '.app' or args.output.exists()): parser.error('Choose a new output path ending in .app.') root = Path(__file__).resolve().parents[2] @@ -83,9 +88,13 @@ if args.snow_leopard: target = root / 'target/snow-leopard' built = target / 'x86_64-apple-macosx10.6' else: - subprocess.run(['cargo', 'build', '-p', 'snowbound'] + profile, cwd=root, check=True) metadata = json.loads(subprocess.check_output(['cargo', 'metadata', '--format-version=1', '--no-deps'], cwd=root)) target = built = Path(metadata['target_directory']) + cross = [] if args.arch == host else ['--target', f'{args.arch}-apple-darwin'] + if cross: + built = target / cross[1] + subprocess.run(['cargo', 'build', '-p', 'snowbound'] + profile + cross, cwd=root, check=True, + env={**os.environ, 'MACOSX_DEPLOYMENT_TARGET': minimum} if args.arch == 'x86_64' else None) bundle = args.output.resolve() if args.output else target / 'Snowbound.app' if args.output: bundle.mkdir(parents=True, exist_ok=False) @@ -107,8 +116,10 @@ if args.snow_leopard: '--out', iconset / f'icon_{side}x{side}.png'], check=True, capture_output=True) subprocess.run(['iconutil', '-c', 'icns', iconset, '-o', resources / 'Snowbound.icns'], check=True) else: - icon = 'Snowbound-Tahoe' if int(platform.mac_ver()[0].split('.')[0] or 0) >= 26 else 'Snowbound-Sequoia' - shutil.copy2(icons / f'{icon}.icns', resources / 'Snowbound.icns') + # macOS 26 draws the Liquid Glass icon from the catalog; it holds no flattened renditions + # (see the icon folder's README), so earlier versions fall back to the icns. + shutil.copy2(icons / 'Snowbound-Sequoia.icns', resources / 'Snowbound.icns') + shutil.copy2(icons / 'Assets.car', resources) # tools/release.py names the build, as 2026-09-29-r10, which About shows. build = os.environ.get('SNOWBOUND_BUILD') versions = {} @@ -126,6 +137,7 @@ if build: 'NSHighResolutionCapable': True, 'NSPrincipalClass': 'NSApplication', 'CFBundleIconFile': 'Snowbound', + 'CFBundleIconName': 'Snowbound-Tahoe', 'NSLocalNetworkUsageDescription': 'Snowbound connects to file servers on your network to open and sync shared notebooks.', 'NSMicrophoneUsageDescription':'Snowbound records audio into your notes when you choose Record Audio or Record Video.', 'NSCameraUsageDescription': 'Snowbound records video into your notes when you choose Record Video.', @@ -134,7 +146,8 @@ if build: 'NSUbiquitousContainerName': 'Snowbound', 'NSUbiquitousContainerSupportedFolderLevels': 'Any', }}, -} | versions | ({'LSMinimumSystemVersion': '10.6'} if args.snow_leopard else {}))) + 'LSMinimumSystemVersion': minimum, +} | versions)) # 10.6 runs the bundle unsigned. if not args.snow_leopard: identity = args.sign != 'ad-hoc' and (args.sign_identity or developer_id()) diff --git a/tools/native/picture-objects.ps1 b/tools/native/picture-objects.ps1 new file mode 100644 index 0000000000000000000000000000000000000000..c5c6bd498e29ad9acb82a7731320c5c1542a1688 --- /dev/null +++ b/tools/native/picture-objects.ps1 @@ -0,0 +1,37 @@ +param([Parameter(Mandatory=$true)][string]$Root, [Parameter(Mandatory=$true)][string]$CloneHost) +# A page of pictures and files, in an outline and on the page, for tagging, linking and OCR +# by hand in the clone: notebook/photo.png, notebook/ocr.png and notebook/notes.txt ride along +# with the section. +Set-StrictMode -Version Latest +$ErrorActionPreference = 'Stop' +& "$PSScriptRoot\cold-current.ps1" -Root $Root -CloneHost $CloneHost +$namespace = 'http://schemas.microsoft.com/office/onenote/2010/onenote' +$notebook = Join-Path $Root 'notebook' +$data = { param($name) [Convert]::ToBase64String([IO.File]::ReadAllBytes((Join-Path $notebook $name))) } +$file = Join-Path $notebook 'notes.txt' +$app = New-Object -ComObject OneNote.Application +$notebookId = '' +try { + $app.OpenHierarchy($notebook, '', [ref]$notebookId, 0) + $sectionId = '' + $app.OpenHierarchy('files.one', $notebookId, [ref]$sectionId, 0) + $pageId = '' + $app.CreateNewPage($sectionId, [ref]$pageId, 0) + $body = '' + $body += '' + $body += '' + $body += '' + (& $data 'photo.png') + '' + $body += '' + $body += '' + $body += '' + $body += '' + (& $data 'photo.png') + '' + $body += '' + $body += '' + (& $data 'ocr.png') + '' + $xml = '' + $body + '' + $app.UpdatePageContent($xml, [DateTime]::MinValue, 1, $true) + $app.SyncHierarchy($notebookId) +} finally { + [void][Runtime.InteropServices.Marshal]::FinalReleaseComObject($app) + [GC]::Collect() + [GC]::WaitForPendingFinalizers() +} diff --git a/tools/native_runner.py b/tools/native_runner.py index 5ca947d7bb6b90c09842a6aefeb215fe4aedf81f..1b2b86aa2eea5279cc28022dd8b51662fc46efe0 100644 --- a/tools/native_runner.py +++ b/tools/native_runner.py @@ -151,7 +151,7 @@ def capture(notebook, output, expected_pages=-1, author=None, screenshots=False, 'author_timeout_seconds': author_timeout, 'inspect': inspect, 'collect_notebook': collect_notebook, - 'base': json.loads(vm.BASE_MANIFEST.read_text()), + 'base': json.loads(vm.base_manifest('win7').read_text()), 'scripts': {name: hashlib.sha256((scripts / name).read_bytes()).hexdigest() for name in sorted(p.name for p in scripts.iterdir())}, }, indent=2) + '\n') diff --git a/tools/release.py b/tools/release.py index 2b52a42e84d1a58d69f6390a288e2792357efb19..02c9dbdc6693e93a3c554eb6bfe917de69399f4f 100755 --- a/tools/release.py +++ b/tools/release.py @@ -17,8 +17,8 @@ PUBLISHED = Path('/Volumes/clover/Documents/Public/Snowbound') URL = 'https://file.paperclover.net/shr/snowbound/' KEY = Path.home() / '.config/snowbound/release-key' ZONE = ZoneInfo('America/Los_Angeles') -PLATFORMS = ['macos-aarch64', 'macos-10.6', 'linux-x86_64', 'linux-aarch64', 'windows-x86_64', - 'windows-aarch64'] +PLATFORMS = ['macos-aarch64', 'macos-x86_64', 'macos-10.6', 'linux-x86_64', 'linux-aarch64', + 'windows-x86_64', 'windows-aarch64'] # Windows 7 to 11 on x86_64 (nightly's tier-3 win7 target), and Windows 11 on Arm. WINDOWS = {'x86_64': 'x86_64-win7-windows-gnu', 'aarch64': 'aarch64-pc-windows-gnullvm'} CHECKS = [ @@ -114,6 +114,8 @@ def build_mac(platform, folder, developer_id, notarize): signing = ['--sign', 'developer-id', '--sign-identity', IDENTITY] else: signing = ['--sign', 'ad-hoc'] + if platform != 'macos-10.6': + signing += ['--arch', platform.removeprefix('macos-')] run([sys.executable, ROOT / 'tools/canvas/build_macos.py', '--release', '--output', bundle, *signing]) archive = folder / 'archive.zip' if notarize and platform != 'macos-10.6': @@ -150,7 +152,7 @@ def main(): parser.add_argument('--ad-hoc', action='store_true', help='Sign the macOS app ad hoc instead of with Developer ID, unnotarized') args = parser.parse_args() - developer_id = not args.ad_hoc and any(platform == 'macos-aarch64' for platform in args.platforms) + developer_id = not args.ad_hoc and any(platform in ('macos-aarch64', 'macos-x86_64') for platform in args.platforms) identities = subprocess.run(['security', 'find-identity', '-v', '-p', 'codesigning'], capture_output=True, text=True).stdout if developer_id and IDENTITY not in identities: diff --git a/tools/test_equation_select.py b/tools/test_equation_select.py new file mode 100644 index 0000000000000000000000000000000000000000..2cd4751bcb4ea86985d7b4133d76e42364c34aa6 --- /dev/null +++ b/tools/test_equation_select.py @@ -0,0 +1,40 @@ +from pathlib import Path +import re +import runpy +import shutil +from tempfile import TemporaryDirectory +import unittest + +ROOT = Path(__file__).resolve().parent.parent +FIXTURE = ROOT / 'corpus/equation-select' +compare = runpy.run_path(str(ROOT / 'tools/verify-document.py'))['compare'] + + +def mathml(path): + """Each equation's MathML in a COM read, trailing spaces dropped.""" + xml = path.read_text(encoding='utf-8-sig') + return [re.sub(r'( )+', '', m).replace(' display="block"', '') + for m in re.findall(r'', xml)] + + +class EquationSelectTest(unittest.TestCase): + def test_edits_into_equation_objects_reopen_as_onenote_made_them(self): + with TemporaryDirectory() as temporary: + read = Path(temporary) / 'read' + shutil.copytree(FIXTURE / 'cold/read', read) + compare(FIXTURE / 'candidate', read) + onenote = mathml(FIXTURE / 'lab/after.xml') + cold = mathml(FIXTURE / 'cold/read/page-000.xml') + # The lab page ends with "x" typed over a placeholder, which the candidate has no + # placeholder left for. + self.assertEqual(onenote[-1], 'x') + self.assertEqual(cold, onenote[:-1]) + before = mathml(FIXTURE / 'lab/before.xml') + self.assertIn('Type equation here.', ''.join(before)) + self.assertTrue(any('' in m for m in before)) + self.assertFalse(any('' in m or 'Type equation' in m for m in cold)) + self.assertTrue(any('' in m and 'lim' in m for m in cold)) + + +if __name__ == '__main__': + unittest.main() diff --git a/tools/test_release.py b/tools/test_release.py index 607dcfe1e59996d1c54388b67cf73a1c1f503eaa..5f1f5a85d59e134c7f69daf3f4c573b927c041db 100644 --- a/tools/test_release.py +++ b/tools/test_release.py @@ -50,9 +50,12 @@ class ReleaseTest(unittest.TestCase): [command[1] for command in commands[1:]]) self.assertEqual(signing('macos-aarch64', True, ['--key-id', 'K']), - (['--sign', 'developer-id', '--sign-identity', release['IDENTITY']], + (['--sign', 'developer-id', '--sign-identity', release['IDENTITY'], '--arch', 'aarch64'], ['-c', 'notarytool', 'stapler', '-c'])) - self.assertEqual(signing('macos-aarch64', False, None), (['--sign', 'ad-hoc'], ['-c'])) + self.assertEqual(signing('macos-x86_64', True, ['--key-id', 'K']), + (['--sign', 'developer-id', '--sign-identity', release['IDENTITY'], '--arch', 'x86_64'], + ['-c', 'notarytool', 'stapler', '-c'])) + self.assertEqual(signing('macos-aarch64', False, None), (['--sign', 'ad-hoc', '--arch', 'aarch64'], ['-c'])) self.assertEqual(signing('macos-10.6', True, ['--key-id', 'K']), (['--snow-leopard'], ['-c'])) finally: scope['run'] = run -- 2.54.0