diff --git a/Packages/Fuziki_NSAttributedTextView/Package.swift b/Packages/Fuziki_NSAttributedTextView/Package.swift index 5a574d6e..aea4a03a 100644 --- a/Packages/Fuziki_NSAttributedTextView/Package.swift +++ b/Packages/Fuziki_NSAttributedTextView/Package.swift @@ -22,5 +22,9 @@ let package = Package( .product(name: "CocoaExtension", package: "vChewing_CocoaExtension"), ] ), + .testTarget( + name: "NSAttributedTextViewTests", + dependencies: ["NSAttributedTextView"] + ), ] ) diff --git a/Packages/Fuziki_NSAttributedTextView/Sources/NSAttributedTextView/NSAttributedTextView.swift b/Packages/Fuziki_NSAttributedTextView/Sources/NSAttributedTextView/NSAttributedTextView.swift index ae4030f5..f2fcaa40 100644 --- a/Packages/Fuziki_NSAttributedTextView/Sources/NSAttributedTextView/NSAttributedTextView.swift +++ b/Packages/Fuziki_NSAttributedTextView/Sources/NSAttributedTextView/NSAttributedTextView.swift @@ -72,6 +72,18 @@ public class NSAttributedTextView: NSView { } } + public init() { + super.init(frame: .zero) + #if compiler(>=5.9) && canImport(AppKit, _version: "14.0") + clipsToBounds = true // 得手動聲明該特性,否則該 View 的尺寸會失控。 + #endif + } + + @available(*, unavailable) + required init?(coder _: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + public func attributedStringValue(areaCalculation: Bool = false) -> NSAttributedString { var newAttributes = attributes let isVertical: Bool = !(direction == .horizontal) @@ -131,8 +143,7 @@ public class NSAttributedTextView: NSView { } override public func draw(_ rect: CGRect) { - let context = NSGraphicsContext.current?.cgContext - guard let context = context else { return } + guard let currentNSGraphicsContext = NSGraphicsContext.current else { return } let setter = CTFramesetterCreateWithAttributedString(attributedStringValue()) let path = CGPath(rect: rect, transform: nil) let theCTFrameProgression: CTFrameProgression = { @@ -152,7 +163,16 @@ public class NSAttributedTextView: NSView { let bgPath: NSBezierPath = .init(roundedRect: rect, xRadius: 0, yRadius: 0) bgPath.fill() currentRect = rect - CTFrameDraw(newFrame, context) + if #unavailable(macOS 10.10) { + // 由於 NSGraphicsContext.current?.cgContext 僅對 macOS 10.10 Yosemite 開始的系統開放, + // 所以這裡必須直接從記憶體位置拿取原始資料來處理。 + let contextPtr: Unmanaged? = Unmanaged.fromOpaque(currentNSGraphicsContext.graphicsPort) + let theContext: CGContext? = contextPtr?.takeUnretainedValue() + guard let theContext = theContext else { return } + CTFrameDraw(newFrame, theContext) + } else { + CTFrameDraw(newFrame, currentNSGraphicsContext.cgContext) + } } } diff --git a/Packages/Fuziki_NSAttributedTextView/Tests/NSAttributedTextViewTests/NSAttributedTextViewTests.swift b/Packages/Fuziki_NSAttributedTextView/Tests/NSAttributedTextViewTests/NSAttributedTextViewTests.swift new file mode 100644 index 00000000..013b2db7 --- /dev/null +++ b/Packages/Fuziki_NSAttributedTextView/Tests/NSAttributedTextViewTests/NSAttributedTextViewTests.swift @@ -0,0 +1,62 @@ +// (c) 2021 and onwards The vChewing Project (MIT-NTL License). +// ==================== +// This code is released under the MIT license (SPDX-License-Identifier: MIT) +// ... with NTL restriction stating that: +// No trademark license is granted to use the trade names, trademarks, service +// marks, or product names of Contributor, except as required to fulfill notice +// requirements defined in MIT License. + +import AppKit +import CocoaExtension +import Foundation +@testable import NSAttributedTextView +import Shared +import XCTest + +class MainAssemblyTests: XCTestCase { + func testView() throws { + let testCtl: testController = .init() + var rect = testCtl.attrView.shrinkFrame() + var bigRect = rect + bigRect.size.width += NSFont.systemFontSize + bigRect.size.height += NSFont.systemFontSize + rect.origin.x += ceil(NSFont.systemFontSize / 2) + rect.origin.y += ceil(NSFont.systemFontSize / 2) + testCtl.attrView.frame = rect + testCtl.window?.setFrame(bigRect, display: true) + testCtl.window?.orderFront(nil) + testCtl.attrView.draw(testCtl.attrView.frame) + testCtl.window?.setIsVisible(true) + } +} + +class testController: NSWindowController { + var attrView: NSAttributedTextView + init() { + let contentRect = NSRect(x: 128.0, y: 128.0, width: 300.0, height: 20.0) + let styleMask: NSWindow.StyleMask = [.borderless, .nonactivatingPanel] + let panel = NSPanel( + contentRect: contentRect, styleMask: styleMask, backing: .buffered, defer: false + ) + panel.level = NSWindow.Level(Int(max(CGShieldingWindowLevel(), kCGPopUpMenuWindowLevel)) + 2) + panel.hasShadow = true + panel.backgroundColor = NSColor.clear + panel.isOpaque = false + panel.isMovable = false + panel.contentView?.wantsLayer = true + panel.contentView?.layer?.cornerRadius = 7 + panel.contentView?.layer?.backgroundColor = NSColor.controlBackgroundColor.cgColor + attrView = NSAttributedTextView() + attrView.backgroundColor = NSColor.clear + attrView.textColor = NSColor.textColor + attrView.needsDisplay = true + attrView.text = "114514" + panel.contentView?.addSubview(attrView) + super.init(window: panel) + } + + @available(*, unavailable) + required init?(coder _: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +}