From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Shelley Vohr <shelley.vohr@gmail.com>
Date: Thu, 20 Aug 2020 10:55:48 -0700
Subject: fix: properly honor printing page ranges

The print ranges in Chromium's print job settings were not being properly
plumbed through to PMPrintSettings on mcOS. This fixes that by setting
them should they exist.

This will be upstreamed.

diff --git a/printing/printing_context_mac.h b/printing/printing_context_mac.h
index 8be4ca70ff71cfc33cd812ec0cc9ae8155538532..f7985331838387232b27e557e435113479dbb780 100644
--- a/printing/printing_context_mac.h
+++ b/printing/printing_context_mac.h
@@ -85,6 +85,10 @@ class COMPONENT_EXPORT(PRINTING) PrintingContextMac : public PrintingContext {
   // Returns true if the orientation was set.
   bool SetOrientationIsLandscape(bool landscape);
 
+  // Set the page range in native print info object.
+  // Returns true if the range was set.
+  bool SetPrintRangeInPrintSettings(const PageRanges& ranges);
+
   // Sets duplex mode in PMPrintSettings.
   // Returns true if duplex mode is set.
   bool SetDuplexModeInPrintSettings(mojom::DuplexMode mode);
diff --git a/printing/printing_context_mac.mm b/printing/printing_context_mac.mm
index 4f15b217fcf8119f323e04596978c6710d73727a..7ffd6c873a4320c76605417819a8b71ffd9ced65 100644
--- a/printing/printing_context_mac.mm
+++ b/printing/printing_context_mac.mm
@@ -543,7 +543,8 @@ bool IsIppColorModelColorful(mojom::ColorModel color_model) {
         !SetCollateInPrintSettings(settings_->collate()) ||
         !SetDuplexModeInPrintSettings(settings_->duplex_mode()) ||
         !SetOutputColor(static_cast<int>(settings_->color())) ||
-        !SetResolution(settings_->dpi_size())) {
+        !SetResolution(settings_->dpi_size()) ||
+        !SetPrintRangeInPrintSettings(settings_->ranges()) ) {
       return OnError();
     }
   }
@@ -696,6 +697,22 @@ bool IsIppColorModelColorful(mojom::ColorModel color_model) {
   return PMSetCopies(print_settings, copies, false) == noErr;
 }
 
+bool PrintingContextMac::SetPrintRangeInPrintSettings(const PageRanges& ranges) {
+  // Default is already NSPrintAllPages - we can safely bail.
+  if (ranges.empty())
+    return true;
+
+  PMPrintSettings print_settings =
+      static_cast<PMPrintSettings>([print_info_ PMPrintSettings]);
+
+  // macOS does not allow multiple ranges, so pluck the first.
+  auto range = ranges.front();
+  bool set_first_page = PMSetFirstPage(print_settings, range.from + 1, false) == noErr;
+  bool set_last_page = PMSetLastPage(print_settings, range.to + 1, false) == noErr;
+
+  return set_first_page && set_last_page;
+}
+
 bool PrintingContextMac::SetCollateInPrintSettings(bool collate) {
   PMPrintSettings print_settings =
       static_cast<PMPrintSettings>([print_info_ PMPrintSettings]);
diff --git a/printing/printing_context_system_dialog_win.cc b/printing/printing_context_system_dialog_win.cc
index f8e903f21cee7041dea67b479c298baf9093d719..ed5d59f29992b0925efd89cb0ac4b33a03a31788 100644
--- a/printing/printing_context_system_dialog_win.cc
+++ b/printing/printing_context_system_dialog_win.cc
@@ -4,10 +4,12 @@
 
 #include "printing/printing_context_system_dialog_win.h"
 
+#include <algorithm>
 #include <utility>
 
 #include "base/auto_reset.h"
 #include "base/compiler_specific.h"
+#include "base/containers/span.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/task/current_thread.h"
 #include "printing/backend/win_helper.h"
@@ -74,13 +76,28 @@ void PrintingContextSystemDialogWin::AskUserForSettings(
   PRINTPAGERANGE ranges[32] = {};
   dialog_options.nStartPage = START_PAGE_GENERAL;
   if (max_pages) {
-    // Default initialize to print all the pages.
-    ranges[0].nFromPage = 1;
-    ranges[0].nToPage = max_pages;
-    dialog_options.nPageRanges = 1;
-    dialog_options.nMaxPageRanges = std::size(ranges);
+    if (const auto& src = settings_->ranges(); !src.empty()) {
+      const auto transform = [](const printing::PageRange& range) {
+        return PRINTPAGERANGE{
+          .nFromPage = range.from + 1U,
+          .nToPage = range.to + 1U
+        };
+      };
+      const size_t n_items = std::min(std::size(src), std::size(ranges));
+      std::ranges::transform(base::span(src).first(n_items), ranges, transform);
+      dialog_options.nPageRanges = n_items;
+
+      // Ensure the Pages radio button is selected.
+      dialog_options.Flags |= PD_PAGENUMS;
+    } else {
+      ranges[0].nFromPage = 1;
+      ranges[0].nToPage = max_pages;
+      dialog_options.nPageRanges = 1;
+    }
+
     dialog_options.nMinPage = 1;
     dialog_options.nMaxPage = max_pages;
+    dialog_options.nMaxPageRanges = std::size(ranges);
     dialog_options.lpPageRanges = ranges;
   } else {
     // No need to bother, we don't know how many pages are available.
diff --git a/ui/gtk/printing/print_dialog_gtk.cc b/ui/gtk/printing/print_dialog_gtk.cc
index 16c80d9ff00089ced6d65dc618316079b9204ba2..96fb7867eb92e19bc8513907124b2cfdaecc4c55 100644
--- a/ui/gtk/printing/print_dialog_gtk.cc
+++ b/ui/gtk/printing/print_dialog_gtk.cc
@@ -21,6 +21,7 @@
 #include "base/memory/ptr_util.h"
 #include "base/memory/raw_ptr.h"
 #include "base/no_destructor.h"
+#include "base/numerics/safe_conversions.h"
 #include "base/sequence_checker.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
@@ -268,6 +269,22 @@ void PrintDialogGtk::UpdateSettings(
 
   gtk_print_settings_set_n_copies(gtk_settings_, settings->copies());
   gtk_print_settings_set_collate(gtk_settings_, settings->collate());
+
+  if (const auto& ranges = settings->ranges(); !ranges.empty()) {
+    // Tell the system that we only intend to print a subset of pages.
+    std::vector<GtkPageRange> granges;
+    granges.reserve(ranges.size());
+    auto transform = [](const printing::PageRange& src) {
+      return GtkPageRange{
+        .start = base::ClampedNumeric<int>(src.from),
+        .end = base::ClampedNumeric<int>(src.to),
+      };
+    };
+    std::ranges::transform(ranges, std::back_inserter(granges), transform);
+    gtk_print_settings_set_print_pages(gtk_settings_, GTK_PRINT_PAGES_RANGES);
+    gtk_print_settings_set_page_ranges(gtk_settings_, granges.data(), granges.size());
+  }
+
   if (settings->dpi_horizontal() > 0 && settings->dpi_vertical() > 0) {
     gtk_print_settings_set_resolution_xy(
         gtk_settings_, settings->dpi_horizontal(), settings->dpi_vertical());
