1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169
|
// Copyright 2011 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "printing/print_settings_initializer_win.h"
#include <windows.h>
#include "base/check_op.h"
#include "base/compiler_specific.h"
#include "printing/backend/win_helper.h"
#include "printing/mojom/print.mojom.h"
#include "printing/print_settings.h"
#include "printing/printing_utils.h"
namespace printing {
namespace {
bool HasEscapeSupport(HDC hdc, DWORD escape) {
const char* ptr = reinterpret_cast<const char*>(&escape);
return ExtEscape(hdc, QUERYESCSUPPORT, sizeof(escape), ptr, 0, nullptr) > 0;
}
bool IsTechnology(HDC hdc, const char* technology) {
if (::GetDeviceCaps(hdc, TECHNOLOGY) != DT_RASPRINTER)
return false;
if (!HasEscapeSupport(hdc, GETTECHNOLOGY))
return false;
char buf[256];
UNSAFE_TODO(memset(buf, 0, sizeof(buf)));
if (ExtEscape(hdc, GETTECHNOLOGY, 0, nullptr, sizeof(buf) - 1, buf) <= 0)
return false;
return UNSAFE_TODO(strcmp(buf, technology)) == 0;
}
void SetPrinterToGdiMode(HDC hdc) {
// Try to set to GDI centric mode
DWORD mode = PSIDENT_GDICENTRIC;
const char* ptr = reinterpret_cast<const char*>(&mode);
ExtEscape(hdc, POSTSCRIPT_IDENTIFY, sizeof(DWORD), ptr, 0, nullptr);
}
int GetPrinterPostScriptLevel(HDC hdc) {
constexpr int param = FEATURESETTING_PSLEVEL;
const char* param_char_ptr = reinterpret_cast<const char*>(¶m);
int param_out = 0;
char* param_out_char_ptr = reinterpret_cast<char*>(¶m_out);
if (ExtEscape(hdc, GET_PS_FEATURESETTING, sizeof(param), param_char_ptr,
sizeof(param_out), param_out_char_ptr) > 0) {
return param_out;
}
return 0;
}
bool IsPrinterPostScript(HDC hdc, int* level) {
static constexpr char kPostScriptDriver[] = "PostScript";
// If printer does not support POSTSCRIPT_IDENTIFY, it cannot be set to GDI
// mode to check the language level supported. See if it looks like a
// postscript printer and supports the postscript functions that are
// supported in compatability mode. If so set to level 2 postscript.
if (!HasEscapeSupport(hdc, POSTSCRIPT_IDENTIFY)) {
if (!IsTechnology(hdc, kPostScriptDriver))
return false;
if (!HasEscapeSupport(hdc, POSTSCRIPT_PASSTHROUGH) ||
!HasEscapeSupport(hdc, POSTSCRIPT_DATA)) {
return false;
}
*level = 2;
return true;
}
// Printer supports POSTSCRIPT_IDENTIFY so we can assume it has a postscript
// driver. Set the printer to GDI mode in order to query the postscript
// level. Use GDI mode instead of PostScript mode so that if level detection
// fails or returns language level < 2 we can fall back to normal printing.
// Note: This escape must be called before other escapes.
SetPrinterToGdiMode(hdc);
if (!HasEscapeSupport(hdc, GET_PS_FEATURESETTING)) {
// Can't query the level, use level 2 to be safe
*level = 2;
return true;
}
// Get the language level. If invalid or < 2, return false to set printer to
// normal printing mode.
*level = GetPrinterPostScriptLevel(hdc);
return *level == 2 || *level == 3;
}
bool IsPrinterXPS(HDC hdc) {
static constexpr char kXPSDriver[] =
"http://schemas.microsoft.com/xps/2005/06";
return IsTechnology(hdc, kXPSDriver);
}
bool IsPrinterTextOnly(HDC hdc) {
return ::GetDeviceCaps(hdc, TECHNOLOGY) == DT_CHARSTREAM;
}
} // namespace
// static
void PrintSettingsInitializerWin::InitPrintSettings(
HDC hdc,
const DEVMODE& dev_mode,
PrintSettings* print_settings) {
DCHECK(hdc);
DCHECK(print_settings);
print_settings->SetOrientation(dev_mode.dmOrientation == DMORIENT_LANDSCAPE);
int dpi_x = GetDeviceCaps(hdc, LOGPIXELSX);
int dpi_y = GetDeviceCaps(hdc, LOGPIXELSY);
print_settings->set_dpi_xy(dpi_x, dpi_y);
int dpi = print_settings->dpi();
DCHECK_EQ(print_settings->device_units_per_inch(), dpi);
DCHECK_EQ(GetDeviceCaps(hdc, SCALINGFACTORX), 0);
DCHECK_EQ(GetDeviceCaps(hdc, SCALINGFACTORY), 0);
// Blink doesn't support different dpi settings in X and Y axis. However,
// some printers use them. So, to avoid a bad page calculation, scale page
// size components based on the dpi in the appropriate dimension.
gfx::Size physical_size_scaled(
GetDeviceCaps(hdc, PHYSICALWIDTH) * dpi / dpi_x,
GetDeviceCaps(hdc, PHYSICALHEIGHT) * dpi / dpi_y);
gfx::Rect printable_area_device_units = GetPrintableAreaDeviceUnits(hdc);
gfx::Rect printable_area_scaled =
gfx::Rect(printable_area_device_units.x() * dpi / dpi_x,
printable_area_device_units.y() * dpi / dpi_y,
printable_area_device_units.width() * dpi / dpi_x,
printable_area_device_units.height() * dpi / dpi_y);
print_settings->SetPrinterPrintableArea(physical_size_scaled,
printable_area_scaled, false);
print_settings->set_color(IsDevModeWithColor(&dev_mode)
? mojom::ColorModel::kColor
: mojom::ColorModel::kGray);
// Check for postscript first so that we can change the mode with the
// first command.
int level;
if (IsPrinterPostScript(hdc, &level)) {
if (level == 2) {
print_settings->set_printer_language_type(
mojom::PrinterLanguageType::kPostscriptLevel2);
return;
}
DCHECK_EQ(3, level);
print_settings->set_printer_language_type(
mojom::PrinterLanguageType::kPostscriptLevel3);
return;
}
// Detects the generic / text only driver.
if (IsPrinterTextOnly(hdc)) {
print_settings->set_printer_language_type(
mojom::PrinterLanguageType::kTextOnly);
return;
}
if (IsPrinterXPS(hdc)) {
print_settings->set_printer_language_type(mojom::PrinterLanguageType::kXps);
return;
}
print_settings->set_printer_language_type(mojom::PrinterLanguageType::kNone);
}
} // namespace printing
|