blob: f30b80ddb1c4dd82ac000dc3d2de2b720bc01c15 [file] [log] [blame]
// Copyright 2020 The PDFium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
#include "core/fxge/win32/cps_printer_driver.h"
#include <stdint.h>
#include <sstream>
#include "core/fxcrt/data_vector.h"
#include "core/fxcrt/fx_system.h"
#include "core/fxcrt/retain_ptr.h"
#include "core/fxge/cfx_fillrenderoptions.h"
#include "core/fxge/cfx_path.h"
#include "core/fxge/dib/cfx_imagerenderer.h"
#include "core/fxge/win32/cpsoutput.h"
#include "third_party/base/check.h"
#include "third_party/base/notreached.h"
namespace {
CFX_PSRenderer::RenderingLevel RenderingLevelFromWindowsPrintMode(
WindowsPrintMode mode) {
switch (mode) {
case WindowsPrintMode::kPostScript2:
case WindowsPrintMode::kPostScript2PassThrough:
return CFX_PSRenderer::RenderingLevel::kLevel2;
case WindowsPrintMode::kPostScript3:
case WindowsPrintMode::kPostScript3PassThrough:
return CFX_PSRenderer::RenderingLevel::kLevel3;
case WindowsPrintMode::kPostScript3Type42:
case WindowsPrintMode::kPostScript3Type42PassThrough:
return CFX_PSRenderer::RenderingLevel::kLevel3Type42;
default:
// |mode| should be PostScript.
NOTREACHED();
return CFX_PSRenderer::RenderingLevel::kLevel2;
}
}
} // namespace
CPSPrinterDriver::CPSPrinterDriver(HDC hDC,
WindowsPrintMode mode,
CFX_PSFontTracker* ps_font_tracker,
const EncoderIface* encoder_iface)
: m_hDC(hDC), m_PSRenderer(ps_font_tracker, encoder_iface) {
CFX_PSRenderer::RenderingLevel level =
RenderingLevelFromWindowsPrintMode(mode);
CPSOutput::OutputMode output_mode =
(mode == WindowsPrintMode::kPostScript2 ||
mode == WindowsPrintMode::kPostScript3 ||
mode == WindowsPrintMode::kPostScript3Type42)
? CPSOutput::OutputMode::kGdiComment
: CPSOutput::OutputMode::kExtEscape;
m_HorzSize = ::GetDeviceCaps(m_hDC, HORZSIZE);
m_VertSize = ::GetDeviceCaps(m_hDC, VERTSIZE);
m_Width = ::GetDeviceCaps(m_hDC, HORZRES);
m_Height = ::GetDeviceCaps(m_hDC, VERTRES);
m_nBitsPerPixel = ::GetDeviceCaps(m_hDC, BITSPIXEL);
m_PSRenderer.Init(pdfium::MakeRetain<CPSOutput>(m_hDC, output_mode), level,
m_Width, m_Height);
HRGN hRgn = ::CreateRectRgn(0, 0, 1, 1);
if (::GetClipRgn(m_hDC, hRgn) == 1) {
DWORD dwCount = ::GetRegionData(hRgn, 0, nullptr);
if (dwCount) {
DataVector<uint8_t> buffer(dwCount);
RGNDATA* pData = reinterpret_cast<RGNDATA*>(buffer.data());
if (::GetRegionData(hRgn, dwCount, pData)) {
CFX_Path path;
for (uint32_t i = 0; i < pData->rdh.nCount; i++) {
RECT* pRect =
reinterpret_cast<RECT*>(pData->Buffer + pData->rdh.nRgnSize * i);
path.AppendRect(static_cast<float>(pRect->left),
static_cast<float>(pRect->bottom),
static_cast<float>(pRect->right),
static_cast<float>(pRect->top));
}
m_PSRenderer.SetClip_PathFill(path, nullptr,
CFX_FillRenderOptions::WindingOptions());
}
}
}
::DeleteObject(hRgn);
}
CPSPrinterDriver::~CPSPrinterDriver() = default;
DeviceType CPSPrinterDriver::GetDeviceType() const {
return DeviceType::kPrinter;
}
int CPSPrinterDriver::GetDeviceCaps(int caps_id) const {
switch (caps_id) {
case FXDC_PIXEL_WIDTH:
return m_Width;
case FXDC_PIXEL_HEIGHT:
return m_Height;
case FXDC_BITS_PIXEL:
return m_nBitsPerPixel;
case FXDC_RENDER_CAPS:
return FXRC_BIT_MASK;
case FXDC_HORZ_SIZE:
return m_HorzSize;
case FXDC_VERT_SIZE:
return m_VertSize;
default:
NOTREACHED();
return 0;
}
}
void CPSPrinterDriver::SaveState() {
m_PSRenderer.SaveState();
}
void CPSPrinterDriver::RestoreState(bool bKeepSaved) {
m_PSRenderer.RestoreState(bKeepSaved);
}
bool CPSPrinterDriver::SetClip_PathFill(
const CFX_Path& path,
const CFX_Matrix* pObject2Device,
const CFX_FillRenderOptions& fill_options) {
m_PSRenderer.SetClip_PathFill(path, pObject2Device, fill_options);
return true;
}
bool CPSPrinterDriver::SetClip_PathStroke(
const CFX_Path& path,
const CFX_Matrix* pObject2Device,
const CFX_GraphStateData* pGraphState) {
m_PSRenderer.SetClip_PathStroke(path, pObject2Device, pGraphState);
return true;
}
bool CPSPrinterDriver::DrawPath(const CFX_Path& path,
const CFX_Matrix* pObject2Device,
const CFX_GraphStateData* pGraphState,
FX_ARGB fill_color,
FX_ARGB stroke_color,
const CFX_FillRenderOptions& fill_options,
BlendMode blend_type) {
if (blend_type != BlendMode::kNormal)
return false;
return m_PSRenderer.DrawPath(path, pObject2Device, pGraphState, fill_color,
stroke_color, fill_options);
}
bool CPSPrinterDriver::GetClipBox(FX_RECT* pRect) {
*pRect = m_PSRenderer.GetClipBox();
return true;
}
bool CPSPrinterDriver::SetDIBits(const RetainPtr<CFX_DIBBase>& pBitmap,
uint32_t color,
const FX_RECT& src_rect,
int left,
int top,
BlendMode blend_type) {
if (blend_type != BlendMode::kNormal)
return false;
return m_PSRenderer.SetDIBits(pBitmap, color, left, top);
}
bool CPSPrinterDriver::StretchDIBits(const RetainPtr<CFX_DIBBase>& pBitmap,
uint32_t color,
int dest_left,
int dest_top,
int dest_width,
int dest_height,
const FX_RECT* pClipRect,
const FXDIB_ResampleOptions& options,
BlendMode blend_type) {
if (blend_type != BlendMode::kNormal)
return false;
return m_PSRenderer.StretchDIBits(pBitmap, color, dest_left, dest_top,
dest_width, dest_height, options);
}
bool CPSPrinterDriver::StartDIBits(const RetainPtr<CFX_DIBBase>& pBitmap,
int bitmap_alpha,
uint32_t color,
const CFX_Matrix& matrix,
const FXDIB_ResampleOptions& options,
std::unique_ptr<CFX_ImageRenderer>* handle,
BlendMode blend_type) {
if (blend_type != BlendMode::kNormal)
return false;
if (bitmap_alpha < 255)
return false;
*handle = nullptr;
return m_PSRenderer.DrawDIBits(pBitmap, color, matrix, options);
}
bool CPSPrinterDriver::DrawDeviceText(
pdfium::span<const TextCharPos> pCharPos,
CFX_Font* pFont,
const CFX_Matrix& mtObject2Device,
float font_size,
uint32_t color,
const CFX_TextRenderOptions& /*options*/) {
return m_PSRenderer.DrawText(pCharPos.size(), pCharPos.data(), pFont,
mtObject2Device, font_size, color);
}
bool CPSPrinterDriver::MultiplyAlpha(float alpha) {
// PostScript doesn't support transparency. All callers are using
// `CFX_DIBitmap`-backed raster devices anyway.
NOTREACHED();
return false;
}
bool CPSPrinterDriver::MultiplyAlpha(const RetainPtr<CFX_DIBBase>& mask) {
// PostScript doesn't support transparency. All callers are using
// `CFX_DIBitmap`-backed raster devices anyway.
NOTREACHED();
return false;
}