| // 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; |
| } |