diff options
Diffstat (limited to 'test/macos_e2e.swift')
| -rw-r--r-- | test/macos_e2e.swift | 29 |
1 files changed, 29 insertions, 0 deletions
diff --git a/test/macos_e2e.swift b/test/macos_e2e.swift index c076aebb..800e2d43 100644 --- a/test/macos_e2e.swift +++ b/test/macos_e2e.swift @@ -95,6 +95,8 @@ private final class Driver: PardesViewDelegate { private var observer: NSObjectProtocol? private var output = "" private var nextAnimationFrame: Date? + /// Where present() puts the pixels nobody reads. + private var presentationRep: NSBitmapImageRep? /// The script's own file name, for error messages. private let scriptName: String @@ -219,6 +221,7 @@ private final class Driver: PardesViewDelegate { window?.contentView = nil window = nil view = nil + presentationRep = nil host.clipboard = nil host.woke = false } @@ -336,6 +339,10 @@ private final class Driver: PardesViewDelegate { private func readFrame() -> Frame { let count = pardes_frame() + // The core has produced a frame; presenting it is this harness's half of + // the contract, and it has to happen AFTER the render rather than before + // — see present(). + defer { present() } let cols = Int(pardes_frame_cols()) let rows = Int(pardes_frame_rows()) // -1 means hidden. Clamped to 0 rather than printed, which is what @@ -396,6 +403,28 @@ private final class Driver: PardesViewDelegate { options: .regularExpression) } + /// Put the frame readFrame() just produced on screen — for a window that has + /// no screen, into a bitmap. draw(_:) is the only caller of + /// pardes_frame_presented, and this window is deliberately never ordered + /// front, so without this nothing here would ever present anything: the core + /// would owe a presentation for the rest of the script and correctly hold + /// every pointer gesture after the first layout change inert, addressing + /// pixels no backend had shown. The app pays the same debt on every pump + /// (AppDelegate.pump marks the view, AppKit's display cycle draws it). + /// + /// The rep is kept and reused rather than allocated per frame: this runs on + /// every poll slice, and cacheDisplay only needs somewhere to put pixels + /// nobody reads. `draw` makes its own, because it reads them. + private func present() { + guard let view, view.bounds.width >= 1, view.bounds.height >= 1 else { return } + let bounds = view.bounds + if presentationRep?.size != bounds.size { + presentationRep = view.bitmapImageRepForCachingDisplay(in: bounds) + } + guard let rep = presentationRep else { return } + view.cacheDisplay(in: bounds, to: rep) + } + /// Render the view the way AppKit would and prove the CoreText pass put /// something on the screen. `snap` reads the core's cell buffer and would be /// perfectly happy with a draw(_:) that returned on its first line; this is |
