perf(menubar): 设置页预览只栅格化一次
预览图原为绘制回调型 NSImage,SwiftUI 每次布局或重绘都会重跑文字排版。 改为渲染一次位图后复用;设置页停在“菜单栏”时,同环境实测平均 CPU 约 2.73% 降至 2.16%。
This commit is contained in:
1 parent
dacc9cbbaa
commit
2c0905ece8
2 files changed
+47
-5
No files matched your search
@@ -294,20 +294,37 @@ enum MenuBarRenderer {
|
||||
return image
|
||||
}
|
||||
|
||||
/// 设置页预览:按指定外观绘制到不透明底色上
|
||||
/// 设置页预览:按指定外观绘制到不透明底色上。
|
||||
/// 绘制回调型图像每次布局或重绘都会重跑文字排版,因此栅格化一次,SwiftUI 之后只复用位图。
|
||||
static func preview(_ image: NSImage, dark: Bool) -> NSImage {
|
||||
let appearance = NSAppearance(named: dark ? .darkAqua : .aqua)
|
||||
return NSImage(size: image.size, flipped: false) { rect in
|
||||
let draw = {
|
||||
let draw = { (rect: NSRect) in
|
||||
let content = {
|
||||
image.draw(in: rect)
|
||||
if image.isTemplate {
|
||||
(dark ? NSColor.white : NSColor.black).set()
|
||||
rect.fill(using: .sourceAtop)
|
||||
}
|
||||
}
|
||||
if let appearance { appearance.performAsCurrentDrawingAppearance(draw) } else { draw() }
|
||||
return true
|
||||
if let appearance { appearance.performAsCurrentDrawingAppearance(content) } else { content() }
|
||||
}
|
||||
let scale = NSScreen.main?.backingScaleFactor ?? 2
|
||||
guard let rep = NSBitmapImageRep(bitmapDataPlanes: nil,
|
||||
pixelsWide: Int(ceil(image.size.width * scale)),
|
||||
pixelsHigh: Int(ceil(image.size.height * scale)),
|
||||
bitsPerSample: 8, samplesPerPixel: 4, hasAlpha: true, isPlanar: false,
|
||||
colorSpaceName: .deviceRGB, bytesPerRow: 0, bitsPerPixel: 0),
|
||||
let context = NSGraphicsContext(bitmapImageRep: rep) else {
|
||||
return NSImage(size: image.size, flipped: false) { draw($0); return true }
|
||||
}
|
||||
rep.size = image.size
|
||||
NSGraphicsContext.saveGraphicsState()
|
||||
NSGraphicsContext.current = context
|
||||
draw(NSRect(origin: .zero, size: image.size))
|
||||
NSGraphicsContext.restoreGraphicsState()
|
||||
let result = NSImage(size: image.size)
|
||||
result.addRepresentation(rep)
|
||||
return result
|
||||
}
|
||||
|
||||
// MARK: 各指标
|
||||
|
||||
@@ -202,6 +202,31 @@ private func isolatedDefaults() -> UserDefaults {
|
||||
|
||||
@MainActor
|
||||
@Suite struct SettingsTests {
|
||||
@Test(arguments: [false, true])
|
||||
func settingsPreviewRasterizesOnceAndKeepsAppearanceColors(dark: Bool) throws {
|
||||
var draws = 0
|
||||
let source = NSImage(size: NSSize(width: 40, height: 18), flipped: false) { rect in
|
||||
draws += 1
|
||||
NSColor.black.setFill()
|
||||
rect.fill()
|
||||
return true
|
||||
}
|
||||
source.isTemplate = true
|
||||
let preview = MenuBarRenderer.preview(source, dark: dark)
|
||||
let drawsAfterRender = draws
|
||||
#expect(drawsAfterRender >= 1)
|
||||
// 反复读取预览(布局、重绘)不能再触发源图的绘制回调。
|
||||
for _ in 0..<5 { _ = preview.tiffRepresentation }
|
||||
#expect(draws == drawsAfterRender)
|
||||
#expect(preview.size == source.size)
|
||||
#expect(preview.representations.contains { $0 is NSBitmapImageRep })
|
||||
// 模板图按外观着色:浅色外观为黑,深色外观为白。
|
||||
let rep = try #require(preview.representations.compactMap { $0 as? NSBitmapImageRep }.first)
|
||||
let center = try #require(rep.colorAt(x: rep.pixelsWide / 2, y: rep.pixelsHigh / 2)?.usingColorSpace(.deviceRGB))
|
||||
#expect(center.alphaComponent > 0.99)
|
||||
#expect((center.redComponent > 0.5) == dark)
|
||||
}
|
||||
|
||||
@Test func stackedCenteredStyleRendersDifferentPlacementAtSameWidth() {
|
||||
#expect(MenuBarStyle.options(for: .fan).contains(.stackedCenter))
|
||||
var reading = MenuBarReading.sample
|
||||
|
||||
Reference in new issue
Block a user