-
Notifications
You must be signed in to change notification settings - Fork 16
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
PDF saving, printing #2247
PDF saving, printing #2247
Changes from all commits
a70b754
27f5ef9
6f9e967
66b8402
d94de89
e8ee236
2dc38b7
84de49b
3016796
c1a5c80
9334b1b
ffe9c0a
bc305a1
fb5be90
d5ff3a5
d96c3b6
b1a1eaf
0f26ab8
54a5f45
529e332
c4af141
04ea192
e01bc85
d6c8400
16f66bc
4fe31fc
37161e5
ffc5269
1086c36
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
// | ||
// WKPDFHUDViewWrapper.swift | ||
// | ||
// Copyright © 2024 DuckDuckGo. All rights reserved. | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
// | ||
|
||
import Foundation | ||
import WebKit | ||
|
||
/// A wrapper for the PDF HUD window with Zoom controls, Download and Open in Preview buttons | ||
/// Used to trigger Save PDF | ||
struct WKPDFHUDViewWrapper { | ||
|
||
static let WKPDFHUDViewClass: AnyClass? = NSClassFromString("WKPDFHUDView") | ||
static let performActionForControlSelector = NSSelectorFromString("_performActionForControl:") | ||
static let visibleKey = "_visible" | ||
static let setVisibleSelector = NSSelectorFromString("_setVisible:") | ||
static let savePDFControlId = "arrow.down.circle" | ||
|
||
private let hudView: NSView | ||
|
||
var isVisible: Bool { | ||
get { | ||
hudView.layer?.sublayers?.first?.opacity ?? 0 > 0 | ||
} | ||
nonmutating set { | ||
guard hudView.responds(to: Self.setVisibleSelector) else { return } | ||
hudView.perform(Self.setVisibleSelector, with: newValue) | ||
} | ||
} | ||
|
||
/// Create a wrapper over the PDF HUD view validating its class is `WKPDFHUDView` | ||
/// - parameter view: the WKPDFHUDView to wrap | ||
/// - returns nil if the view | ||
init?(view: NSView) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Suggestion: Would be good to add some markdown documentation for the two |
||
guard type(of: view) == Self.WKPDFHUDViewClass else { return nil } | ||
|
||
guard Self.WKPDFHUDViewClass?.instancesRespond(to: Self.performActionForControlSelector) == true else { | ||
assertionFailure("WKPDFHUDView doesn‘t respond to _performActionForControl:") | ||
return nil | ||
} | ||
self.hudView = view | ||
} | ||
|
||
/// Find WebView‘s PDF HUD view at a clicked point | ||
/// | ||
/// Used to get PDF controls view of a clicked WebView frame for `Print…` and `Save As…` PDF context menu commands | ||
static func getPdfHudView(in webView: WKWebView, at location: NSPoint? = nil) -> Self? { | ||
guard let hudView = webView.subviews.last(where: { type(of: $0) == Self.WKPDFHUDViewClass && $0.frame.contains(location ?? $0.frame.origin) }) else { | ||
#if DEBUG | ||
Task { | ||
if await webView.mimeType == "application/pdf" { | ||
assertionFailure("WebView doesn‘t have PDF HUD View") | ||
} | ||
} | ||
#endif | ||
return nil | ||
} | ||
return self.init(view: hudView) | ||
} | ||
|
||
func savePDF() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is it possible to test this behaviour? |
||
let wasVisible = isVisible | ||
self.setIsVisibleIVar(true) | ||
defer { | ||
if !wasVisible { | ||
self.setIsVisibleIVar(false) | ||
} | ||
} | ||
hudView.perform(Self.performActionForControlSelector, with: Self.savePDFControlId) | ||
} | ||
|
||
// try to set _visible ivar value directly to avoid actually showing the HUD | ||
private func setIsVisibleIVar(_ value: Bool) { | ||
do { | ||
try NSException.catch { | ||
hudView.setValue(value, forKey: Self.visibleKey) | ||
} | ||
} catch { | ||
assertionFailure("\(error)") | ||
self.isVisible = value | ||
} | ||
} | ||
|
||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suggestion: can probably make these static let private as they don’t have to be accessed by/known to the outside
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
used in availability tests