mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-29 15:52:07 +00:00
Bug 1090448 - nsDeviceContextSpecG should not use GtkPrinter until the print job is ready. r=karlt.
In the multi-process case, we might need to query the system (and maybe the network) for a printer with a name matching the one we're looking for. In order to not spin an event loop at dangerous times (since searching for printers is either asynchronous, or requires an event loop), we defer searching for the printer until we've already finished reflowing and rendering the document to be printed. --HG-- extra : rebase_source : 5cd11982e47d3f7cb61fe697e54e310fe1a8d244
This commit is contained in:
parent
7ce830fbd1
commit
24affce8d1
@ -80,9 +80,7 @@ nsTArray<nsString>* GlobalPrinters::mGlobalPrinterList = nullptr;
|
||||
//---------------
|
||||
|
||||
nsDeviceContextSpecGTK::nsDeviceContextSpecGTK()
|
||||
: mPrintJob(nullptr)
|
||||
, mGtkPrinter(nullptr)
|
||||
, mGtkPrintSettings(nullptr)
|
||||
: mGtkPrintSettings(nullptr)
|
||||
, mGtkPageSetup(nullptr)
|
||||
{
|
||||
DO_PR_DEBUG_LOG(("nsDeviceContextSpecGTK::nsDeviceContextSpecGTK()\n"));
|
||||
@ -120,6 +118,10 @@ NS_IMETHODIMP nsDeviceContextSpecGTK::GetSurfaceForPrinter(gfxASurface **aSurfac
|
||||
DO_PR_DEBUG_LOG(("\"%s\", %f, %f\n", mPath, width, height));
|
||||
nsresult rv;
|
||||
|
||||
// We shouldn't be attempting to get a surface if we've already got a spool
|
||||
// file.
|
||||
MOZ_ASSERT(!mSpoolFile);
|
||||
|
||||
// Spool file. Use Glib's temporary file function since we're
|
||||
// already dependent on the gtk software stack.
|
||||
gchar *buf;
|
||||
@ -158,28 +160,19 @@ NS_IMETHODIMP nsDeviceContextSpecGTK::GetSurfaceForPrinter(gfxASurface **aSurfac
|
||||
format = nsIPrintSettings::kOutputFormatPS;
|
||||
} else {
|
||||
const gchar* fmtGTK = gtk_print_settings_get(mGtkPrintSettings, GTK_PRINT_SETTINGS_OUTPUT_FILE_FORMAT);
|
||||
if (!fmtGTK && GTK_IS_PRINTER(mGtkPrinter)) {
|
||||
// Likely not print-to-file, check printer's capabilities
|
||||
|
||||
// Prior to gtk 2.24, gtk_printer_accepts_pdf() and
|
||||
// gtk_printer_accepts_ps() always returned true regardless of the
|
||||
// printer's capability.
|
||||
if (gtk_major_version > 2 ||
|
||||
(gtk_major_version == 2 && gtk_minor_version >= 24)) {
|
||||
format =
|
||||
gtk_printer_accepts_pdf(mGtkPrinter) ?
|
||||
static_cast<int16_t>(nsIPrintSettings::kOutputFormatPDF) :
|
||||
static_cast<int16_t>(nsIPrintSettings::kOutputFormatPS);
|
||||
if (fmtGTK) {
|
||||
if (nsDependentCString(fmtGTK).EqualsIgnoreCase("pdf")) {
|
||||
format = nsIPrintSettings::kOutputFormatPDF;
|
||||
} else {
|
||||
format = nsIPrintSettings::kOutputFormatPS;
|
||||
}
|
||||
|
||||
} else if (nsDependentCString(fmtGTK).EqualsIgnoreCase("pdf")) {
|
||||
format = nsIPrintSettings::kOutputFormatPDF;
|
||||
} else {
|
||||
format = nsIPrintSettings::kOutputFormatPS;
|
||||
}
|
||||
}
|
||||
|
||||
// If we haven't found the format at this point, we're sunk. :(
|
||||
if (format == nsIPrintSettings::kOutputFormatNative) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
if (format == nsIPrintSettings::kOutputFormatPDF) {
|
||||
@ -217,7 +210,10 @@ NS_IMETHODIMP nsDeviceContextSpecGTK::Init(nsIWidget *aWidget,
|
||||
(gtk_major_version == 2 && gtk_minor_version < 10))
|
||||
return NS_ERROR_NOT_AVAILABLE; // I'm so sorry bz
|
||||
|
||||
mPrintSettings = aPS;
|
||||
mPrintSettings = do_QueryInterface(aPS);
|
||||
if (!mPrintSettings)
|
||||
return NS_ERROR_NO_INTERFACE;
|
||||
|
||||
mIsPPreview = aIsPrintPreview;
|
||||
|
||||
// This is only set by embedders
|
||||
@ -226,13 +222,8 @@ NS_IMETHODIMP nsDeviceContextSpecGTK::Init(nsIWidget *aWidget,
|
||||
|
||||
mToPrinter = !toFile && !aIsPrintPreview;
|
||||
|
||||
nsCOMPtr<nsPrintSettingsGTK> printSettingsGTK(do_QueryInterface(aPS));
|
||||
if (!printSettingsGTK)
|
||||
return NS_ERROR_NO_INTERFACE;
|
||||
|
||||
mGtkPrinter = printSettingsGTK->GetGtkPrinter();
|
||||
mGtkPrintSettings = printSettingsGTK->GetGtkPrintSettings();
|
||||
mGtkPageSetup = printSettingsGTK->GetGtkPageSetup();
|
||||
mGtkPrintSettings = mPrintSettings->GetGtkPrintSettings();
|
||||
mGtkPageSetup = mPrintSettings->GetGtkPageSetup();
|
||||
|
||||
// This is a horrible workaround for some printer driver bugs that treat custom page sizes different
|
||||
// to standard ones. If our paper object matches one of a standard one, use a standard paper size
|
||||
@ -279,31 +270,81 @@ ns_release_macro(gpointer aData) {
|
||||
NS_RELEASE(spoolFile);
|
||||
}
|
||||
|
||||
/* static */
|
||||
gboolean nsDeviceContextSpecGTK::PrinterEnumerator(GtkPrinter *aPrinter,
|
||||
gpointer aData) {
|
||||
nsDeviceContextSpecGTK *spec = (nsDeviceContextSpecGTK*)aData;
|
||||
|
||||
// Find the printer whose name matches the one inside the settings.
|
||||
nsXPIDLString printerName;
|
||||
nsresult rv =
|
||||
spec->mPrintSettings->GetPrinterName(getter_Copies(printerName));
|
||||
if (NS_SUCCEEDED(rv) && printerName) {
|
||||
NS_ConvertUTF16toUTF8 requestedName(printerName);
|
||||
const char* currentName = gtk_printer_get_name(aPrinter);
|
||||
if (requestedName.Equals(currentName)) {
|
||||
nsDeviceContextSpecGTK::StartPrintJob(spec, aPrinter);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
// We haven't found it yet - keep searching...
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* static */
|
||||
void nsDeviceContextSpecGTK::StartPrintJob(nsDeviceContextSpecGTK* spec,
|
||||
GtkPrinter* printer) {
|
||||
GtkPrintJob* job = gtk_print_job_new(spec->mTitle.get(),
|
||||
printer,
|
||||
spec->mGtkPrintSettings,
|
||||
spec->mGtkPageSetup);
|
||||
|
||||
if (!gtk_print_job_set_source_file(job, spec->mSpoolName.get(), nullptr))
|
||||
return;
|
||||
|
||||
NS_ADDREF(spec->mSpoolFile.get());
|
||||
gtk_print_job_send(job, print_callback, spec->mSpoolFile, ns_release_macro);
|
||||
}
|
||||
|
||||
void
|
||||
nsDeviceContextSpecGTK::EnumeratePrinters()
|
||||
{
|
||||
gtk_enumerate_printers(&nsDeviceContextSpecGTK::PrinterEnumerator, this,
|
||||
nullptr, TRUE);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsDeviceContextSpecGTK::BeginDocument(const nsAString& aTitle, char16_t * aPrintToFileName,
|
||||
int32_t aStartPage, int32_t aEndPage)
|
||||
{
|
||||
if (mToPrinter) {
|
||||
if (!GTK_IS_PRINTER(mGtkPrinter))
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
mPrintJob = gtk_print_job_new(NS_ConvertUTF16toUTF8(aTitle).get(), mGtkPrinter,
|
||||
mGtkPrintSettings, mGtkPageSetup);
|
||||
}
|
||||
|
||||
mTitle.Truncate();
|
||||
AppendUTF16toUTF8(aTitle, mTitle);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsDeviceContextSpecGTK::EndDocument()
|
||||
{
|
||||
if (mToPrinter) {
|
||||
if (!mPrintJob)
|
||||
return NS_OK; // The operation was aborted.
|
||||
// At this point, we might have a GtkPrinter set up in nsPrintSettingsGTK,
|
||||
// or we might not. In the single-process case, we probably will, as this
|
||||
// is populated by the print settings dialog, or set to the default
|
||||
// printer.
|
||||
// In the multi-process case, we proxy the print settings dialog over to
|
||||
// the parent process, and only get the name of the printer back on the
|
||||
// content process side. In that case, we need to enumerate the printers
|
||||
// on the content side, and find a printer with a matching name.
|
||||
|
||||
if (!gtk_print_job_set_source_file(mPrintJob, mSpoolName.get(), nullptr))
|
||||
return NS_ERROR_GFX_PRINTER_COULD_NOT_OPEN_FILE;
|
||||
|
||||
NS_ADDREF(mSpoolFile.get());
|
||||
gtk_print_job_send(mPrintJob, print_callback, mSpoolFile, ns_release_macro);
|
||||
GtkPrinter* printer = mPrintSettings->GetGtkPrinter();
|
||||
if (printer) {
|
||||
// We have a printer, so we can print right away.
|
||||
nsDeviceContextSpecGTK::StartPrintJob(this, printer);
|
||||
} else {
|
||||
// We don't have a printer. We have to enumerate the printers and find
|
||||
// one with a matching name.
|
||||
nsCOMPtr<nsIRunnable> event =
|
||||
NS_NewRunnableMethod(this, &nsDeviceContextSpecGTK::EnumeratePrinters);
|
||||
NS_DispatchToCurrentThread(event);
|
||||
}
|
||||
} else {
|
||||
// Handle print-to-file ourselves for the benefit of embedders
|
||||
nsXPIDLString targetPath;
|
||||
|
@ -27,6 +27,8 @@ typedef enum
|
||||
pmPostScript
|
||||
} PrintMethod;
|
||||
|
||||
class nsPrintSettingsGTK;
|
||||
|
||||
class nsDeviceContextSpecGTK : public nsIDeviceContextSpec
|
||||
{
|
||||
public:
|
||||
@ -45,22 +47,26 @@ public:
|
||||
NS_IMETHOD EndPage() MOZ_OVERRIDE { return NS_OK; }
|
||||
|
||||
static nsresult GetPrintMethod(const char *aPrinter, PrintMethod &aMethod);
|
||||
|
||||
|
||||
protected:
|
||||
virtual ~nsDeviceContextSpecGTK();
|
||||
nsCOMPtr<nsIPrintSettings> mPrintSettings;
|
||||
nsCOMPtr<nsPrintSettingsGTK> mPrintSettings;
|
||||
bool mToPrinter : 1; /* If true, print to printer */
|
||||
bool mIsPPreview : 1; /* If true, is print preview */
|
||||
char mPath[PATH_MAX]; /* If toPrinter = false, dest file */
|
||||
char mPrinter[256]; /* Printer name */
|
||||
GtkPrintJob* mPrintJob;
|
||||
GtkPrinter* mGtkPrinter;
|
||||
GtkPrintSettings* mGtkPrintSettings;
|
||||
GtkPageSetup* mGtkPageSetup;
|
||||
|
||||
nsCString mSpoolName;
|
||||
nsCOMPtr<nsIFile> mSpoolFile;
|
||||
nsCString mTitle;
|
||||
|
||||
private:
|
||||
void EnumeratePrinters();
|
||||
static gboolean PrinterEnumerator(GtkPrinter *aPrinter, gpointer aData);
|
||||
static void StartPrintJob(nsDeviceContextSpecGTK *spec,
|
||||
GtkPrinter *printer);
|
||||
};
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
|
@ -198,8 +198,19 @@ nsPrintSettingsGTK::SetGtkPrinter(GtkPrinter *aPrinter)
|
||||
{
|
||||
if (mGTKPrinter)
|
||||
g_object_unref(mGTKPrinter);
|
||||
|
||||
|
||||
mGTKPrinter = (GtkPrinter*) g_object_ref(aPrinter);
|
||||
|
||||
// Prior to gtk 2.24, gtk_printer_accepts_pdf() and
|
||||
// gtk_printer_accepts_ps() always returned true regardless of the
|
||||
// printer's capability.
|
||||
bool shouldTrustGTK =
|
||||
(gtk_major_version > 2 ||
|
||||
(gtk_major_version == 2 && gtk_minor_version >= 24));
|
||||
bool acceptsPDF = shouldTrustGTK && gtk_printer_accepts_pdf(mGTKPrinter);
|
||||
|
||||
SetOutputFormat(acceptsPDF ? nsIPrintSettings::kOutputFormatPDF
|
||||
: nsIPrintSettings::kOutputFormatPS);
|
||||
}
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user