summaryrefslogtreecommitdiff
path: root/test/macos_e2e.swift
diff options
context:
space:
mode:
Diffstat (limited to 'test/macos_e2e.swift')
-rw-r--r--test/macos_e2e.swift62
1 files changed, 62 insertions, 0 deletions
diff --git a/test/macos_e2e.swift b/test/macos_e2e.swift
index 58ad5206..fbfa0e3e 100644
--- a/test/macos_e2e.swift
+++ b/test/macos_e2e.swift
@@ -270,6 +270,15 @@ private final class Driver: PardesViewDelegate {
if let view, let wanted = pardes_font_take(&fontSize) {
view.adoptFont(path: String(cString: wanted), sizeHundredths: fontSize)
}
+ // The app reads both of these every pump too (AppDelegate.applyTheme).
+ // There is no window here to dress, but the VIEW half is the same and
+ // the drawing depends on it: without this a `Theme` or a
+ // `WindowOpacity` in a script would move the core's settings and never
+ // reach a pixel, and the capture would record the old ground forever.
+ if let view {
+ view.adoptThemeBG(pardes_theme_bg())
+ view.adoptWindowOpacity(pardes_window_opacity())
+ }
}
/// Hand the run loop a slice. Main-queue work (anything the view defers)
@@ -489,6 +498,51 @@ private final class Driver: PardesViewDelegate {
output += "== draw \(label) \(w)x\(h) nonblank\n"
}
+ /// The alpha range of a drawn frame, recorded into the golden.
+ ///
+ /// The contract WindowOpacity states (shaders/ui.frag.glsl, and
+ /// PardesView.backgroundAlpha for this shell) is two-sided, so one number
+ /// could not express it: BACKGROUNDS take the setting, and glyph ink stays
+ /// opaque. A minimum below 255 is the ground letting the desktop through;
+ /// a maximum of 255 is the ink still sitting on top of it. At
+ /// `WindowOpacity 100` both ends are 255 and the view is opaque again.
+ private func drawOpacity(_ label: String) throws {
+ let view = try live()
+ let bounds = view.bounds
+ guard let rep = view.bitmapImageRepForCachingDisplay(in: bounds) else {
+ throw ScriptError(message: "draw-opacity \(label): the view would not make a bitmap for \(bounds.size)")
+ }
+ view.cacheDisplay(in: bounds, to: rep)
+ guard let data = rep.bitmapData, rep.pixelsWide > 0, rep.pixelsHigh > 0 else {
+ throw ScriptError(message: "draw-opacity \(label): cacheDisplay produced no pixels")
+ }
+ guard rep.hasAlpha, rep.bitsPerPixel == 32 else {
+ // An opaque view caches into a rep with no alpha at all, which is
+ // itself the answer at WindowOpacity 100 — say so rather than
+ // reporting a range read out of the wrong byte.
+ output += "== draw-opacity \(label) \(Int(bounds.width.rounded()))x\(Int(bounds.height.rounded())) opaque\n"
+ return
+ }
+ // Where alpha sits depends on the rep's format, and only the two
+ // AppKit actually hands back here are worth decoding.
+ let alphaFirst = rep.bitmapFormat.contains(.alphaFirst)
+ let offset = alphaFirst ? 0 : 3
+ let rowBytes = rep.bytesPerRow
+ var lowest: UInt8 = 255
+ var highest: UInt8 = 0
+ for y in 0..<rep.pixelsHigh {
+ let row = data + y * rowBytes
+ for x in 0..<rep.pixelsWide {
+ let alpha = row[x * 4 + offset]
+ if alpha < lowest { lowest = alpha }
+ if alpha > highest { highest = alpha }
+ }
+ }
+ let w = Int(bounds.width.rounded())
+ let h = Int(bounds.height.rounded())
+ output += "== draw-opacity \(label) \(w)x\(h) alpha \(lowest)..\(highest)\n"
+ }
+
// MARK: - the script
func run(source: String) throws -> String {
@@ -799,6 +853,14 @@ private final class Driver: PardesViewDelegate {
guard !rest.isEmpty else { throw ScriptError(message: "draw needs a label") }
try draw(rest)
+ // What WindowOpacity actually did to the pixels, which is the only
+ // place it can be checked: the core's cell buffer says nothing about
+ // alpha, and `draw` deliberately compares channels without knowing
+ // which one is which.
+ case "draw-opacity":
+ guard !rest.isEmpty else { throw ScriptError(message: "draw-opacity needs a label") }
+ try drawOpacity(rest)
+
case "draw-effect":
let view = try live()
guard !rest.isEmpty else { throw ScriptError(message: "draw-effect needs a label") }