1 // Copyright 2020 The PDFium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6
7 #include "core/fxge/win32/cps_printer_driver.h"
8
9 #include <stdint.h>
10
11 #include <sstream>
12 #include <utility>
13
14 #include "core/fxcrt/check.h"
15 #include "core/fxcrt/compiler_specific.h"
16 #include "core/fxcrt/data_vector.h"
17 #include "core/fxcrt/fx_system.h"
18 #include "core/fxcrt/notreached.h"
19 #include "core/fxcrt/retain_ptr.h"
20 #include "core/fxge/agg/cfx_agg_imagerenderer.h"
21 #include "core/fxge/cfx_fillrenderoptions.h"
22 #include "core/fxge/cfx_path.h"
23 #include "core/fxge/dib/cfx_dibbase.h"
24 #include "core/fxge/dib/cfx_dibitmap.h"
25 #include "core/fxge/win32/cpsoutput.h"
26
27 namespace {
28
RenderingLevelFromWindowsPrintMode(WindowsPrintMode mode)29 CFX_PSRenderer::RenderingLevel RenderingLevelFromWindowsPrintMode(
30 WindowsPrintMode mode) {
31 switch (mode) {
32 case WindowsPrintMode::kPostScript2:
33 case WindowsPrintMode::kPostScript2PassThrough:
34 return CFX_PSRenderer::RenderingLevel::kLevel2;
35 case WindowsPrintMode::kPostScript3:
36 case WindowsPrintMode::kPostScript3PassThrough:
37 return CFX_PSRenderer::RenderingLevel::kLevel3;
38 case WindowsPrintMode::kPostScript3Type42:
39 case WindowsPrintMode::kPostScript3Type42PassThrough:
40 return CFX_PSRenderer::RenderingLevel::kLevel3Type42;
41 default:
42 // |mode| should be PostScript.
43 NOTREACHED_NORETURN();
44 }
45 }
46
47 } // namespace
48
CPSPrinterDriver(HDC hDC,WindowsPrintMode mode,CFX_PSFontTracker * ps_font_tracker,const EncoderIface * encoder_iface)49 CPSPrinterDriver::CPSPrinterDriver(HDC hDC,
50 WindowsPrintMode mode,
51 CFX_PSFontTracker* ps_font_tracker,
52 const EncoderIface* encoder_iface)
53 : m_hDC(hDC), m_PSRenderer(ps_font_tracker, encoder_iface) {
54 CFX_PSRenderer::RenderingLevel level =
55 RenderingLevelFromWindowsPrintMode(mode);
56 CPSOutput::OutputMode output_mode =
57 (mode == WindowsPrintMode::kPostScript2 ||
58 mode == WindowsPrintMode::kPostScript3 ||
59 mode == WindowsPrintMode::kPostScript3Type42)
60 ? CPSOutput::OutputMode::kGdiComment
61 : CPSOutput::OutputMode::kExtEscape;
62
63 m_HorzSize = ::GetDeviceCaps(m_hDC, HORZSIZE);
64 m_VertSize = ::GetDeviceCaps(m_hDC, VERTSIZE);
65 m_Width = ::GetDeviceCaps(m_hDC, HORZRES);
66 m_Height = ::GetDeviceCaps(m_hDC, VERTRES);
67 m_nBitsPerPixel = ::GetDeviceCaps(m_hDC, BITSPIXEL);
68
69 m_PSRenderer.Init(pdfium::MakeRetain<CPSOutput>(m_hDC, output_mode), level,
70 m_Width, m_Height);
71 HRGN hRgn = ::CreateRectRgn(0, 0, 1, 1);
72 if (::GetClipRgn(m_hDC, hRgn) == 1) {
73 DWORD dwCount = ::GetRegionData(hRgn, 0, nullptr);
74 if (dwCount) {
75 DataVector<uint8_t> buffer(dwCount);
76 RGNDATA* pData = reinterpret_cast<RGNDATA*>(buffer.data());
77 if (::GetRegionData(hRgn, dwCount, pData)) {
78 CFX_Path path;
79 for (uint32_t i = 0; i < pData->rdh.nCount; i++) {
80 RECT* pRect = UNSAFE_TODO(
81 reinterpret_cast<RECT*>(pData->Buffer + pData->rdh.nRgnSize * i));
82 path.AppendRect(static_cast<float>(pRect->left),
83 static_cast<float>(pRect->bottom),
84 static_cast<float>(pRect->right),
85 static_cast<float>(pRect->top));
86 }
87 m_PSRenderer.SetClip_PathFill(path, nullptr,
88 CFX_FillRenderOptions::WindingOptions());
89 }
90 }
91 }
92 ::DeleteObject(hRgn);
93 }
94
95 CPSPrinterDriver::~CPSPrinterDriver() = default;
96
GetDeviceType() const97 DeviceType CPSPrinterDriver::GetDeviceType() const {
98 return DeviceType::kPrinter;
99 }
100
GetDeviceCaps(int caps_id) const101 int CPSPrinterDriver::GetDeviceCaps(int caps_id) const {
102 switch (caps_id) {
103 case FXDC_PIXEL_WIDTH:
104 return m_Width;
105 case FXDC_PIXEL_HEIGHT:
106 return m_Height;
107 case FXDC_BITS_PIXEL:
108 return m_nBitsPerPixel;
109 case FXDC_RENDER_CAPS:
110 return 0;
111 case FXDC_HORZ_SIZE:
112 return m_HorzSize;
113 case FXDC_VERT_SIZE:
114 return m_VertSize;
115 default:
116 NOTREACHED_NORETURN();
117 }
118 }
119
SaveState()120 void CPSPrinterDriver::SaveState() {
121 m_PSRenderer.SaveState();
122 }
123
RestoreState(bool bKeepSaved)124 void CPSPrinterDriver::RestoreState(bool bKeepSaved) {
125 m_PSRenderer.RestoreState(bKeepSaved);
126 }
127
SetClip_PathFill(const CFX_Path & path,const CFX_Matrix * pObject2Device,const CFX_FillRenderOptions & fill_options)128 bool CPSPrinterDriver::SetClip_PathFill(
129 const CFX_Path& path,
130 const CFX_Matrix* pObject2Device,
131 const CFX_FillRenderOptions& fill_options) {
132 m_PSRenderer.SetClip_PathFill(path, pObject2Device, fill_options);
133 return true;
134 }
135
SetClip_PathStroke(const CFX_Path & path,const CFX_Matrix * pObject2Device,const CFX_GraphStateData * pGraphState)136 bool CPSPrinterDriver::SetClip_PathStroke(
137 const CFX_Path& path,
138 const CFX_Matrix* pObject2Device,
139 const CFX_GraphStateData* pGraphState) {
140 m_PSRenderer.SetClip_PathStroke(path, pObject2Device, pGraphState);
141 return true;
142 }
143
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)144 bool CPSPrinterDriver::DrawPath(const CFX_Path& path,
145 const CFX_Matrix* pObject2Device,
146 const CFX_GraphStateData* pGraphState,
147 FX_ARGB fill_color,
148 FX_ARGB stroke_color,
149 const CFX_FillRenderOptions& fill_options) {
150 return m_PSRenderer.DrawPath(path, pObject2Device, pGraphState, fill_color,
151 stroke_color, fill_options);
152 }
153
GetClipBox() const154 FX_RECT CPSPrinterDriver::GetClipBox() const {
155 return m_PSRenderer.GetClipBox();
156 }
157
SetDIBits(RetainPtr<const CFX_DIBBase> bitmap,uint32_t color,const FX_RECT & src_rect,int left,int top,BlendMode blend_type)158 bool CPSPrinterDriver::SetDIBits(RetainPtr<const CFX_DIBBase> bitmap,
159 uint32_t color,
160 const FX_RECT& src_rect,
161 int left,
162 int top,
163 BlendMode blend_type) {
164 if (blend_type != BlendMode::kNormal)
165 return false;
166 return m_PSRenderer.SetDIBits(std::move(bitmap), color, left, top);
167 }
168
StretchDIBits(RetainPtr<const CFX_DIBBase> bitmap,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)169 bool CPSPrinterDriver::StretchDIBits(RetainPtr<const CFX_DIBBase> bitmap,
170 uint32_t color,
171 int dest_left,
172 int dest_top,
173 int dest_width,
174 int dest_height,
175 const FX_RECT* pClipRect,
176 const FXDIB_ResampleOptions& options,
177 BlendMode blend_type) {
178 return blend_type == BlendMode::kNormal &&
179 m_PSRenderer.StretchDIBits(std::move(bitmap), color, dest_left,
180 dest_top, dest_width, dest_height, options);
181 }
182
StartDIBits(RetainPtr<const CFX_DIBBase> bitmap,float alpha,uint32_t color,const CFX_Matrix & matrix,const FXDIB_ResampleOptions & options,BlendMode blend_type)183 RenderDeviceDriverIface::StartResult CPSPrinterDriver::StartDIBits(
184 RetainPtr<const CFX_DIBBase> bitmap,
185 float alpha,
186 uint32_t color,
187 const CFX_Matrix& matrix,
188 const FXDIB_ResampleOptions& options,
189 BlendMode blend_type) {
190 if (blend_type != BlendMode::kNormal || alpha != 1.0f) {
191 return {Result::kNotSupported, nullptr};
192 }
193
194 bool success =
195 m_PSRenderer.DrawDIBits(std::move(bitmap), color, matrix, options);
196 return {success ? Result::kSuccess : Result::kFailure, nullptr};
197 }
198
DrawDeviceText(pdfium::span<const TextCharPos> pCharPos,CFX_Font * pFont,const CFX_Matrix & mtObject2Device,float font_size,uint32_t color,const CFX_TextRenderOptions &)199 bool CPSPrinterDriver::DrawDeviceText(
200 pdfium::span<const TextCharPos> pCharPos,
201 CFX_Font* pFont,
202 const CFX_Matrix& mtObject2Device,
203 float font_size,
204 uint32_t color,
205 const CFX_TextRenderOptions& /*options*/) {
206 return m_PSRenderer.DrawText(pCharPos.size(), pCharPos.data(), pFont,
207 mtObject2Device, font_size, color);
208 }
209
MultiplyAlpha(float alpha)210 bool CPSPrinterDriver::MultiplyAlpha(float alpha) {
211 // PostScript doesn't support transparency. All callers are using
212 // `CFX_DIBitmap`-backed raster devices anyway.
213 NOTREACHED_NORETURN();
214 }
215
MultiplyAlphaMask(RetainPtr<const CFX_DIBitmap> mask)216 bool CPSPrinterDriver::MultiplyAlphaMask(RetainPtr<const CFX_DIBitmap> mask) {
217 // PostScript doesn't support transparency. All callers are using
218 // `CFX_DIBitmap`-backed raster devices anyway.
219 NOTREACHED_NORETURN();
220 }
221