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