Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions printing/ios/printing/Sources/printing/PrintJob.swift
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,8 @@ public class PrintJob: UIPrintPageRenderer, UIPrintInteractionControllerDelegate
controller.delegate = self

let printInfo = UIPrintInfo.printInfo()
printInfo.jobName = jobName!
let strippedJobName = jobName!.hasSuffix(".pdf") ? String(jobName!.dropLast(4)) : jobName!
printInfo.jobName = strippedJobName
printInfo.outputType = .general
if orientation != nil {
printInfo.orientation = orientation!
Expand Down Expand Up @@ -185,7 +186,8 @@ public class PrintJob: UIPrintPageRenderer, UIPrintInteractionControllerDelegate
orientation = UIPrintInfo.Orientation.landscape
}

jobName = name
// Strip .pdf extension as UIPrintInteractionController appends it automatically
jobName = name.hasSuffix(".pdf") ? String(name.dropLast(4)) : name
printerName = printerID

let controller = UIPrintInteractionController.shared
Expand Down
24 changes: 18 additions & 6 deletions printing/ios/printing/Sources/printing/PrintingPlugin.swift
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,9 @@ public class PrintingPlugin: NSObject, FlutterPlugin {
"job": printJob.index,
] as [String: Any]

channel.invokeMethod("onLayout", arguments: arg)
DispatchQueue.main.async {
self.channel.invokeMethod("onLayout", arguments: arg)
}
}

/// send completion status to flutter
Expand All @@ -195,8 +197,10 @@ public class PrintingPlugin: NSObject, FlutterPlugin {
"error": error as Any,
"job": printJob.index,
]
channel.invokeMethod("onCompleted", arguments: data)
jobs.removeValue(forKey: UInt32(printJob.index))
DispatchQueue.main.async {
self.channel.invokeMethod("onCompleted", arguments: data)
}
}

/// send html to pdf data result to flutter
Expand All @@ -205,7 +209,9 @@ public class PrintingPlugin: NSObject, FlutterPlugin {
"doc": FlutterStandardTypedData(bytes: pdfData),
"job": printJob.index,
]
channel.invokeMethod("onHtmlRendered", arguments: data)
DispatchQueue.main.async {
self.channel.invokeMethod("onHtmlRendered", arguments: data)
}
}

/// send html to pdf conversion error to flutter
Expand All @@ -214,7 +220,9 @@ public class PrintingPlugin: NSObject, FlutterPlugin {
"error": error,
"job": printJob.index,
]
channel.invokeMethod("onHtmlError", arguments: data)
DispatchQueue.main.async {
self.channel.invokeMethod("onHtmlError", arguments: data)
}
}

/// send pdf to raster data result to flutter
Expand All @@ -225,14 +233,18 @@ public class PrintingPlugin: NSObject, FlutterPlugin {
"height": height,
"job": printJob.index,
]
channel.invokeMethod("onPageRasterized", arguments: data)
DispatchQueue.main.async {
self.channel.invokeMethod("onPageRasterized", arguments: data)
}
}

public func onPageRasterEnd(printJob: PrintJob, error: String?) {
let data: NSDictionary = [
"job": printJob.index,
"error": error as Any,
]
channel.invokeMethod("onPageRasterEnd", arguments: data)
DispatchQueue.main.async {
self.channel.invokeMethod("onPageRasterEnd", arguments: data)
}
}
}
3 changes: 2 additions & 1 deletion printing/lib/src/print_job.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/

import 'dart:async';
import 'dart:math';
import 'dart:typed_data';

import 'callback.dart';
Expand Down Expand Up @@ -57,7 +58,7 @@ class PrintJobs {
/// Create a list print jobs
PrintJobs();

static var _currentIndex = 0;
static int _currentIndex = Random().nextInt(0x7FFFFFFF);

final _printJobs = <int, PrintJob>{};

Expand Down
49 changes: 40 additions & 9 deletions printing/macos/printing/Sources/printing/PrintJob.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,11 @@ public class PrintJob: NSView, NSSharingServicePickerDelegate {
private var printOperation: NSPrintOperation?
private var pdfDocument: CGPDFDocument?
private var page: CGPDFPage?
private let semaphore = DispatchSemaphore(value: 0)
private var isWaitingForDocument = false
private var documentReceived = false
private var dynamic = false
private var _window: NSWindow?
private var lastLayoutParams: (width: CGFloat, height: CGFloat, marginLeft: CGFloat, marginTop: CGFloat, marginRight: CGFloat, marginBottom: CGFloat)?

public init(printing: PrintingPlugin, index: Int) {
self.printing = printing
Expand All @@ -44,6 +46,13 @@ public class PrintJob: NSView, NSSharingServicePickerDelegate {
fatalError("init(coder:) has not been implemented")
}

private func layoutParamsChanged(_ new: (width: CGFloat, height: CGFloat, marginLeft: CGFloat, marginTop: CGFloat, marginRight: CGFloat, marginBottom: CGFloat)) -> Bool {
guard let last = lastLayoutParams else { return true }
return last.width != new.width || last.height != new.height ||
last.marginLeft != new.marginLeft || last.marginTop != new.marginTop ||
last.marginRight != new.marginRight || last.marginBottom != new.marginBottom
}

// Return the number of pages available for printing
override public func knowsPageRange(_ range: NSRangePointer) -> Bool {
let size = printOperation!.showsPrintPanel ? printOperation!.printPanel.printInfo.paperSize : printOperation!.printInfo.paperSize
Expand All @@ -52,18 +61,38 @@ public class PrintJob: NSView, NSSharingServicePickerDelegate {
setBoundsSize(size)

if dynamic {
printing.onLayout(
printJob: self,
let currentParams = (
width: printOperation!.printInfo.paperSize.width,
height: printOperation!.printInfo.paperSize.height,
marginLeft: printOperation!.printInfo.leftMargin,
marginTop: printOperation!.printInfo.topMargin,
marginRight: printOperation!.printInfo.rightMargin,
marginBottom: printOperation!.printInfo.bottomMargin
)

// Block the main thread, waiting for a document
semaphore.wait()

if layoutParamsChanged(currentParams) {
lastLayoutParams = currentParams

printing.onLayout(
printJob: self,
width: currentParams.width,
height: currentParams.height,
marginLeft: currentParams.marginLeft,
marginTop: currentParams.marginTop,
marginRight: currentParams.marginRight,
marginBottom: currentParams.marginBottom
)

// Wait for document using RunLoop to keep main thread responsive
isWaitingForDocument = true
documentReceived = false
let runLoop = RunLoop.current
let timeout = Date(timeIntervalSinceNow: 30.0)
while !documentReceived && Date() < timeout {
runLoop.run(mode: .default, before: Date(timeIntervalSinceNow: 0.1))
}
isWaitingForDocument = false
}
}

if pdfDocument != nil {
Expand Down Expand Up @@ -95,8 +124,8 @@ public class PrintJob: NSView, NSSharingServicePickerDelegate {
pdfDocument = CGPDFDocument(dataProvider!)

if dynamic {
// Unblock the main thread
semaphore.signal()
// Signal that document is ready
documentReceived = true
return
}

Expand Down Expand Up @@ -136,6 +165,7 @@ public class PrintJob: NSView, NSSharingServicePickerDelegate {
public func printPdf(name: String, withPageSize size: CGSize, andMargin _: CGRect, withPrinter printer: String?, dynamically dyn: Bool, andWindow window: NSWindow) {
dynamic = dyn
_window = window
lastLayoutParams = nil
let sharedInfo = NSPrintInfo.shared
let sharedDict = sharedInfo.dictionary()
let printInfoDict = NSMutableDictionary(dictionary: sharedDict)
Expand Down Expand Up @@ -184,8 +214,9 @@ public class PrintJob: NSView, NSSharingServicePickerDelegate {

func cancelJob(_ error: String?) {
pdfDocument = nil
lastLayoutParams = nil
if dynamic {
semaphore.signal()
documentReceived = true
} else {
printing.onCompleted(printJob: self, completed: false, error: error as NSString?)
}
Expand Down
24 changes: 19 additions & 5 deletions printing/macos/printing/Sources/printing/PrintingPlugin.swift
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,9 @@ public func net_nfet_printing_set_error(job: UInt32, message: UnsafePointer<CCha
public class PrintingPlugin: NSObject, FlutterPlugin {
private static var instance: PrintingPlugin?
private var channel: FlutterMethodChannel
public var jobs = [UInt32: PrintJob]()
// Shared jobs across all plugin instances (for multi-window support)
private static var sharedJobs = [UInt32: PrintJob]()
private static let jobsLock = NSLock()
private var registrar: FlutterPluginRegistrar

init(_ channel: FlutterMethodChannel, _ registrar: FlutterPluginRegistrar) {
Expand All @@ -49,12 +51,18 @@ public class PrintingPlugin: NSObject, FlutterPlugin {

@objc
public static func setDocument(job: UInt32, doc: UnsafePointer<UInt8>, size: UInt64) {
instance!.jobs[job]?.setDocument(Data(bytes: doc, count: Int(size)))
jobsLock.lock()
let printJob = sharedJobs[job]
jobsLock.unlock()
printJob?.setDocument(Data(bytes: doc, count: Int(size)))
}

@objc
public static func setError(job: UInt32, message: UnsafePointer<CChar>) {
instance!.jobs[job]?.cancelJob(String(cString: message))
jobsLock.lock()
let printJob = sharedJobs[job]
jobsLock.unlock()
printJob?.cancelJob(String(cString: message))
}

/// Entry point
Expand All @@ -78,7 +86,10 @@ public class PrintingPlugin: NSObject, FlutterPlugin {
let marginBottom = CGFloat((args["marginBottom"] as! NSNumber).floatValue)
let printJob = PrintJob(printing: self, index: args["job"] as! Int)
let dynamic = args["dynamic"] as! Bool
jobs[args["job"] as! UInt32] = printJob

PrintingPlugin.jobsLock.lock()
PrintingPlugin.sharedJobs[args["job"] as! UInt32] = printJob
PrintingPlugin.jobsLock.unlock()

guard let window = registrar.view?.window else {
result(NSNumber(value: 0))
Expand Down Expand Up @@ -191,7 +202,10 @@ public class PrintingPlugin: NSObject, FlutterPlugin {
"job": printJob.index,
]
channel.invokeMethod("onCompleted", arguments: data)
jobs.removeValue(forKey: UInt32(printJob.index))

PrintingPlugin.jobsLock.lock()
PrintingPlugin.sharedJobs.removeValue(forKey: UInt32(printJob.index))
PrintingPlugin.jobsLock.unlock()
}

/// send html to pdf data result to flutter
Expand Down