Bug 1717292 - Prefer ppd to ipp to custom names in GTK code. r=AlaskanEmily

Try to find a PPD paper size from our IPP paper size to workaround print
driver bugs.

Before:

  Apr 25 18:43:47 ryzen cupsd[850753]: cupsdProcessIPPRequest: media keyword 'iso_a4_210x297mm'

After:

  Apr 25 19:22:54 ryzen cupsd[850753]: cupsdProcessIPPRequest: PageSize nameWithoutLanguage 'A4'

Differential Revision: https://phabricator.services.mozilla.com/D144606
This commit is contained in:
Emilio Cobos Álvarez 2022-04-26 03:36:32 +00:00
Родитель 9788952c5a
Коммит b1878d8eee
2 изменённых файлов: 63 добавлений и 34 удалений

Просмотреть файл

@ -9,6 +9,7 @@
// Provides GUniquePtr to g_free a given pointer.
#include <glib.h>
#include <gtk/gtk.h>
#include "mozilla/UniquePtr.h"
namespace mozilla {
@ -17,6 +18,7 @@ struct GFreeDeleter {
constexpr GFreeDeleter() = default;
void operator()(GError* aPtr) const { g_error_free(aPtr); }
void operator()(void* aPtr) const { g_free(aPtr); }
void operator()(GtkPaperSize* aPtr) const { gtk_paper_size_free(aPtr); }
};
template <typename T>

Просмотреть файл

@ -8,6 +8,7 @@
#include "mozilla/gfx/PrintTargetPDF.h"
#include "mozilla/Logging.h"
#include "mozilla/Services.h"
#include "mozilla/GUniquePtr.h"
#include "mozilla/WidgetUtilsGtk.h"
#include "plstr.h"
@ -124,14 +125,15 @@ struct {
#undef DECLARE_KNOWN_MONOCHROME_SETTING
// https://developer.gnome.org/gtk3/stable/GtkPaperSize.html#gtk-paper-size-new-from-ipp
static GtkPaperSize* GtkPaperSizeFromIpp(const gchar* aIppName, gdouble aWidth,
gdouble aHeight) {
static GUniquePtr<GtkPaperSize> GtkPaperSizeFromIpp(const gchar* aIppName,
gdouble aWidth,
gdouble aHeight) {
static auto sPtr = (GtkPaperSize * (*)(const gchar*, gdouble, gdouble))
dlsym(RTLD_DEFAULT, "gtk_paper_size_new_from_ipp");
if (gtk_check_version(3, 16, 0)) {
return nullptr;
}
return sPtr(aIppName, aWidth, aHeight);
return GUniquePtr<GtkPaperSize>(sPtr(aIppName, aWidth, aHeight));
}
static bool PaperSizeAlmostEquals(GtkPaperSize* aSize,
@ -149,43 +151,70 @@ static bool PaperSizeAlmostEquals(GtkPaperSize* aSize,
return true;
}
// 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 object instead.
// Prefer the ppd name because some printers don't deal well even with standard
// ipp names.
static GUniquePtr<GtkPaperSize> PpdSizeFromIppName(const gchar* aIppName) {
static constexpr struct {
const char* mCups;
const char* mGtk;
} kMap[] = {
{CUPS_MEDIA_A3, GTK_PAPER_NAME_A3},
{CUPS_MEDIA_A4, GTK_PAPER_NAME_A4},
{CUPS_MEDIA_A5, GTK_PAPER_NAME_A5},
{CUPS_MEDIA_LETTER, GTK_PAPER_NAME_LETTER},
{CUPS_MEDIA_LEGAL, GTK_PAPER_NAME_LEGAL},
// Other gtk sizes with no standard CUPS constant: _EXECUTIVE and _B5
};
for (const auto& entry : kMap) {
if (!strcmp(entry.mCups, aIppName)) {
return GUniquePtr<GtkPaperSize>(gtk_paper_size_new(entry.mGtk));
}
}
return nullptr;
}
// 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 object instead.
//
// See bug 414314 and bug 1691798 for more info.
static GtkPaperSize* GetStandardGtkPaperSize(GtkPaperSize* aGeckoPaperSize) {
// We prefer ppd to ipp to custom sizes.
//
// See bug 414314, bug 1691798, and bug 1717292 for more info.
static GUniquePtr<GtkPaperSize> GetStandardGtkPaperSize(
GtkPaperSize* aGeckoPaperSize) {
// We should get an ipp name from cups, try to get a ppd from that first.
const gchar* geckoName = gtk_paper_size_get_name(aGeckoPaperSize);
// We try ipp size first because that's the names we get from CUPS, and
// because even though gtk_paper_size_new deals with ipp, it has rounding
// issues, see https://gitlab.gnome.org/GNOME/gtk/-/issues/3685.
GtkPaperSize* size = GtkPaperSizeFromIpp(
geckoName, gtk_paper_size_get_width(aGeckoPaperSize, GTK_UNIT_POINTS),
gtk_paper_size_get_height(aGeckoPaperSize, GTK_UNIT_POINTS));
if (size && !gtk_paper_size_is_custom(size)) {
return size;
if (auto ppd = PpdSizeFromIppName(geckoName)) {
return ppd;
}
if (size) {
gtk_paper_size_free(size);
}
size = gtk_paper_size_new(geckoName);
if (gtk_paper_size_is_equal(size, aGeckoPaperSize)) {
return size;
// We try gtk_paper_size_new_from_ipp next, because even though
// gtk_paper_size_new tries to deal with ipp, it has some rounding issues that
// the ipp equivalent doesn't have, see
// https://gitlab.gnome.org/GNOME/gtk/-/issues/3685.
if (auto ipp = GtkPaperSizeFromIpp(
geckoName, gtk_paper_size_get_width(aGeckoPaperSize, GTK_UNIT_POINTS),
gtk_paper_size_get_height(aGeckoPaperSize, GTK_UNIT_POINTS))) {
if (!gtk_paper_size_is_custom(ipp.get())) {
if (auto ppd = PpdSizeFromIppName(gtk_paper_size_get_name(ipp.get()))) {
return ppd;
}
return ipp;
}
}
GUniquePtr<GtkPaperSize> size(gtk_paper_size_new(geckoName));
// gtk_paper_size_is_equal compares just paper names. The name in Gecko
// might come from CUPS, which is an ipp size, and gets normalized by gtk.
//
// So check also for the same actual paper size.
if (PaperSizeAlmostEquals(aGeckoPaperSize, size)) {
if (gtk_paper_size_is_equal(size.get(), aGeckoPaperSize) ||
PaperSizeAlmostEquals(aGeckoPaperSize, size.get())) {
return size;
}
// Not the same after all, so use our custom paper size.
gtk_paper_size_free(size);
// Not the same after all, so use our custom paper sizes instead.
return nullptr;
}
@ -206,7 +235,8 @@ NS_IMETHODIMP nsDeviceContextSpecGTK::Init(nsIWidget* aWidget,
mGtkPageSetup = mPrintSettings->GetGtkPageSetup();
GtkPaperSize* geckoPaperSize = gtk_page_setup_get_paper_size(mGtkPageSetup);
GtkPaperSize* gtkPaperSize = GetStandardGtkPaperSize(geckoPaperSize);
GUniquePtr<GtkPaperSize> gtkPaperSize =
GetStandardGtkPaperSize(geckoPaperSize);
mGtkPageSetup = gtk_page_setup_copy(mGtkPageSetup);
mGtkPrintSettings = gtk_print_settings_copy(mGtkPrintSettings);
@ -225,14 +255,11 @@ NS_IMETHODIMP nsDeviceContextSpecGTK::Init(nsIWidget* aWidget,
nsPrinterCUPS::ForEachExtraMonochromeSetting(applySetting);
}
GtkPaperSize* properPaperSize = gtkPaperSize ? gtkPaperSize : geckoPaperSize;
GtkPaperSize* properPaperSize =
gtkPaperSize ? gtkPaperSize.get() : geckoPaperSize;
gtk_print_settings_set_paper_size(mGtkPrintSettings, properPaperSize);
gtk_page_setup_set_paper_size_and_default_margins(mGtkPageSetup,
properPaperSize);
if (gtkPaperSize) {
gtk_paper_size_free(gtkPaperSize);
}
return NS_OK;
}