NS_IMETHODIMP nsDeviceContextSpecGTK::BeginDocument(PRUnichar * aTitle, PRUnichar * aPrintToFileName,
                                                    PRInt32 aStartPage, PRInt32 aEndPage)
{
  if (mToPrinter) {
    if (!GTK_IS_PRINTER(mGtkPrinter))
      return NS_ERROR_FAILURE;

    mPrintJob = gtk_print_job_new(NS_ConvertUTF16toUTF8(aTitle).get(), mGtkPrinter,
                                  mGtkPrintSettings, mGtkPageSetup);
  }

  return NS_OK;
}
NS_IMETHODIMP
nsPrintSettingsGTK::SetupSilentPrinting()
{
    // We have to get a printer here, rather than when the print settings are constructed.
    // This is because when we request sync, GTK makes us wait in the *event loop* while waiting
    // for the enumeration to finish. We must do this when event loop runs are expected.
    gtk_enumerate_printers(printer_enumerator, this, nullptr, TRUE);

    // XXX If no default printer set, get the first one.
    if (!GTK_IS_PRINTER(mGTKPrinter))
        gtk_enumerate_printers(ref_printer, this, nullptr, TRUE);

    return NS_OK;
}
NS_IMETHODIMP
nsPrintSettingsGTK::GetPrinterName(char16_t * *aPrinter)
{
    const char* gtkPrintName = gtk_print_settings_get_printer(mPrintSettings);
    if (!gtkPrintName) {
        if (GTK_IS_PRINTER(mGTKPrinter)) {
            gtkPrintName = gtk_printer_get_name(mGTKPrinter);
        } else {
            // This mimics what nsPrintSettingsImpl does when we try to Get before we Set
            nsXPIDLString nullPrintName;
            *aPrinter = ToNewUnicode(nullPrintName);
            return NS_OK;
        }
    }
    *aPrinter = ToNewUnicode(nsDependentCString(gtkPrintName));
    return NS_OK;
}
NS_IMETHODIMP nsPrintSettingsGTK::GetOutputFormat(int16_t *aOutputFormat)
{
  NS_ENSURE_ARG_POINTER(aOutputFormat);

  int16_t format;
  nsresult rv = nsPrintSettings::GetOutputFormat(&format);
  if (NS_FAILED(rv)) {
    return rv;
  }

  if (format == nsIPrintSettings::kOutputFormatNative) {
    const gchar* fmtGTK =
      gtk_print_settings_get(mPrintSettings,
                             GTK_PRINT_SETTINGS_OUTPUT_FILE_FORMAT);
    if (fmtGTK) {
      if (nsDependentCString(fmtGTK).EqualsIgnoreCase("pdf")) {
        format = nsIPrintSettings::kOutputFormatPDF;
      } else {
        format = nsIPrintSettings::kOutputFormatPS;
      }
    } else if (GTK_IS_PRINTER(mGTKPrinter)) {
      // 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);

      format = acceptsPDF ? nsIPrintSettings::kOutputFormatPDF
                          : nsIPrintSettings::kOutputFormatPS;
    }
  }

  *aOutputFormat = format;
  return NS_OK;
}
NS_IMETHODIMP nsDeviceContextSpecGTK::GetSurfaceForPrinter(gfxASurface **aSurface)
{
  *aSurface = nsnull;

  const char *path;
  GetPath(&path);

  double width, height;
  mPrintSettings->GetEffectivePageSize(&width, &height);

  // If we're in landscape mode, we'll be rotating the output --
  // need to swap width & height.
  PRInt32 orientation;
  mPrintSettings->GetOrientation(&orientation);
  if (nsIPrintSettings::kLandscapeOrientation == orientation) {
    double tmp = width;
    width = height;
    height = tmp;
  }

  // convert twips to points
  width  /= TWIPS_PER_POINT_FLOAT;
  height /= TWIPS_PER_POINT_FLOAT;

  DO_PR_DEBUG_LOG(("\"%s\", %f, %f\n", path, width, height));
  nsresult rv;

  // Spool file. Use Glib's temporary file function since we're
  // already dependent on the gtk software stack.
  gchar *buf;
  gint fd = g_file_open_tmp("XXXXXX.tmp", &buf, nsnull);
  if (-1 == fd)
    return NS_ERROR_GFX_PRINTER_COULD_NOT_OPEN_FILE;
  close(fd);

  rv = NS_NewNativeLocalFile(nsDependentCString(buf), PR_FALSE,
                             getter_AddRefs(mSpoolFile));
  if (NS_FAILED(rv)) {
    unlink(buf);
    return NS_ERROR_GFX_PRINTER_COULD_NOT_OPEN_FILE;
  }

  mSpoolName = buf;
  g_free(buf);

  mSpoolFile->SetPermissions(0600);

  nsCOMPtr<nsIFileOutputStream> stream = do_CreateInstance("@mozilla.org/network/file-output-stream;1");
  rv = stream->Init(mSpoolFile, -1, -1, 0);
  if (NS_FAILED(rv))
    return rv;

  PRInt16 format;
  mPrintSettings->GetOutputFormat(&format);

  nsRefPtr<gfxASurface> surface;
  gfxSize surfaceSize(width, height);

  // Determine the real format with some GTK magic
  if (format == nsIPrintSettings::kOutputFormatNative) {
    if (mIsPPreview) {
      // There is nothing to detect on Print Preview, use PS.
      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
        format = (gtk_printer_accepts_ps(mGtkPrinter)) ? nsIPrintSettings::kOutputFormatPS
                                                       : nsIPrintSettings::kOutputFormatPDF;
      } else if (nsDependentCString(fmtGTK).EqualsIgnoreCase("pdf")) {
          format = nsIPrintSettings::kOutputFormatPDF;
      } else {
          format = nsIPrintSettings::kOutputFormatPS;
      }
    }
  }

  if (format == nsIPrintSettings::kOutputFormatPDF) {
    surface = new gfxPDFSurface(stream, surfaceSize);
  } else {
    surface = new gfxPSSurface(stream, surfaceSize);
  }

  if (!surface)
    return NS_ERROR_OUT_OF_MEMORY;

  surface.swap(*aSurface);

  return NS_OK;
}