1 // Copyright 2014 PDFium Authors. All rights reserved.
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 <windows.h>
8
9 #include <algorithm>
10 #include <memory>
11 #include <vector>
12
13 #include "core/fxcrt/fx_system.h"
14 #include "core/fxge/cfx_font.h"
15 #include "core/fxge/cfx_windowsrenderdevice.h"
16 #include "core/fxge/dib/cfx_dibextractor.h"
17 #include "core/fxge/dib/cfx_dibitmap.h"
18 #include "core/fxge/dib/cfx_imagerenderer.h"
19 #include "core/fxge/dib/cstretchengine.h"
20 #include "core/fxge/fx_freetype.h"
21 #include "core/fxge/text_char_pos.h"
22 #include "core/fxge/win32/cpsoutput.h"
23 #include "core/fxge/win32/win32_int.h"
24 #include "third_party/base/span.h"
25
26 #if defined(PDFIUM_PRINT_TEXT_WITH_GDI)
27 namespace {
28
29 class ScopedState {
30 public:
ScopedState(HDC hDC,HFONT hFont)31 ScopedState(HDC hDC, HFONT hFont)
32 : m_hDC(hDC),
33 m_iState(SaveDC(m_hDC)),
34 m_hFont(SelectObject(m_hDC, hFont)) {}
35
36 ScopedState(const ScopedState&) = delete;
37 ScopedState& operator=(const ScopedState&) = delete;
38
~ScopedState()39 ~ScopedState() {
40 HGDIOBJ hFont = SelectObject(m_hDC, m_hFont);
41 DeleteObject(hFont);
42 RestoreDC(m_hDC, m_iState);
43 }
44
45 private:
46 const HDC m_hDC;
47 const int m_iState;
48 const HGDIOBJ m_hFont;
49 };
50
51 } // namespace
52
53 bool g_pdfium_print_text_with_gdi = false;
54
55 PDFiumEnsureTypefaceCharactersAccessible g_pdfium_typeface_accessible_func =
56 nullptr;
57 #endif
58
CGdiPrinterDriver(HDC hDC)59 CGdiPrinterDriver::CGdiPrinterDriver(HDC hDC)
60 : CGdiDeviceDriver(hDC, DeviceType::kPrinter),
61 m_HorzSize(::GetDeviceCaps(m_hDC, HORZSIZE)),
62 m_VertSize(::GetDeviceCaps(m_hDC, VERTSIZE)) {}
63
64 CGdiPrinterDriver::~CGdiPrinterDriver() = default;
65
GetDeviceCaps(int caps_id) const66 int CGdiPrinterDriver::GetDeviceCaps(int caps_id) const {
67 if (caps_id == FXDC_HORZ_SIZE)
68 return m_HorzSize;
69 if (caps_id == FXDC_VERT_SIZE)
70 return m_VertSize;
71 return CGdiDeviceDriver::GetDeviceCaps(caps_id);
72 }
73
SetDIBits(const RetainPtr<CFX_DIBBase> & pSource,uint32_t color,const FX_RECT & src_rect,int left,int top,BlendMode blend_type)74 bool CGdiPrinterDriver::SetDIBits(const RetainPtr<CFX_DIBBase>& pSource,
75 uint32_t color,
76 const FX_RECT& src_rect,
77 int left,
78 int top,
79 BlendMode blend_type) {
80 if (pSource->IsAlphaMask()) {
81 FX_RECT clip_rect(left, top, left + src_rect.Width(),
82 top + src_rect.Height());
83 return StretchDIBits(pSource, color, left - src_rect.left,
84 top - src_rect.top, pSource->GetWidth(),
85 pSource->GetHeight(), &clip_rect,
86 FXDIB_ResampleOptions(), BlendMode::kNormal);
87 }
88 ASSERT(pSource);
89 ASSERT(!pSource->IsAlphaMask());
90 ASSERT(blend_type == BlendMode::kNormal);
91 if (pSource->HasAlpha())
92 return false;
93
94 CFX_DIBExtractor temp(pSource);
95 RetainPtr<CFX_DIBitmap> pBitmap = temp.GetBitmap();
96 if (!pBitmap)
97 return false;
98
99 return GDI_SetDIBits(pBitmap, src_rect, left, top);
100 }
101
StretchDIBits(const RetainPtr<CFX_DIBBase> & pSource,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)102 bool CGdiPrinterDriver::StretchDIBits(const RetainPtr<CFX_DIBBase>& pSource,
103 uint32_t color,
104 int dest_left,
105 int dest_top,
106 int dest_width,
107 int dest_height,
108 const FX_RECT* pClipRect,
109 const FXDIB_ResampleOptions& options,
110 BlendMode blend_type) {
111 if (pSource->IsAlphaMask()) {
112 int alpha = FXARGB_A(color);
113 if (pSource->GetBPP() != 1 || alpha != 255)
114 return false;
115
116 if (dest_width < 0 || dest_height < 0) {
117 RetainPtr<CFX_DIBitmap> pFlipped =
118 pSource->FlipImage(dest_width < 0, dest_height < 0);
119 if (!pFlipped)
120 return false;
121
122 if (dest_width < 0)
123 dest_left += dest_width;
124 if (dest_height < 0)
125 dest_top += dest_height;
126
127 return GDI_StretchBitMask(pFlipped, dest_left, dest_top, abs(dest_width),
128 abs(dest_height), color);
129 }
130
131 CFX_DIBExtractor temp(pSource);
132 RetainPtr<CFX_DIBitmap> pBitmap = temp.GetBitmap();
133 if (!pBitmap)
134 return false;
135 return GDI_StretchBitMask(pBitmap, dest_left, dest_top, dest_width,
136 dest_height, color);
137 }
138
139 if (pSource->HasAlpha())
140 return false;
141
142 if (dest_width < 0 || dest_height < 0) {
143 RetainPtr<CFX_DIBitmap> pFlipped =
144 pSource->FlipImage(dest_width < 0, dest_height < 0);
145 if (!pFlipped)
146 return false;
147
148 if (dest_width < 0)
149 dest_left += dest_width;
150 if (dest_height < 0)
151 dest_top += dest_height;
152
153 return GDI_StretchDIBits(pFlipped, dest_left, dest_top, abs(dest_width),
154 abs(dest_height), options);
155 }
156
157 CFX_DIBExtractor temp(pSource);
158 RetainPtr<CFX_DIBitmap> pBitmap = temp.GetBitmap();
159 if (!pBitmap)
160 return false;
161 return GDI_StretchDIBits(pBitmap, dest_left, dest_top, dest_width,
162 dest_height, options);
163 }
164
StartDIBits(const RetainPtr<CFX_DIBBase> & pSource,int bitmap_alpha,uint32_t color,const CFX_Matrix & matrix,const FXDIB_ResampleOptions & options,std::unique_ptr<CFX_ImageRenderer> * handle,BlendMode blend_type)165 bool CGdiPrinterDriver::StartDIBits(const RetainPtr<CFX_DIBBase>& pSource,
166 int bitmap_alpha,
167 uint32_t color,
168 const CFX_Matrix& matrix,
169 const FXDIB_ResampleOptions& options,
170 std::unique_ptr<CFX_ImageRenderer>* handle,
171 BlendMode blend_type) {
172 if (bitmap_alpha < 255 || pSource->HasAlpha() ||
173 (pSource->IsAlphaMask() && (pSource->GetBPP() != 1))) {
174 return false;
175 }
176 CFX_FloatRect unit_rect = matrix.GetUnitRect();
177 FX_RECT full_rect = unit_rect.GetOuterRect();
178 if (fabs(matrix.b) < 0.5f && matrix.a != 0 && fabs(matrix.c) < 0.5f &&
179 matrix.d != 0) {
180 bool bFlipX = matrix.a < 0;
181 bool bFlipY = matrix.d > 0;
182 return StretchDIBits(pSource, color,
183 bFlipX ? full_rect.right : full_rect.left,
184 bFlipY ? full_rect.bottom : full_rect.top,
185 bFlipX ? -full_rect.Width() : full_rect.Width(),
186 bFlipY ? -full_rect.Height() : full_rect.Height(),
187 nullptr, FXDIB_ResampleOptions(), blend_type);
188 }
189 if (fabs(matrix.a) >= 0.5f || fabs(matrix.d) >= 0.5f)
190 return false;
191
192 RetainPtr<CFX_DIBitmap> pTransformed =
193 pSource->SwapXY(matrix.c > 0, matrix.b < 0);
194 if (!pTransformed)
195 return false;
196
197 return StretchDIBits(pTransformed, color, full_rect.left, full_rect.top,
198 full_rect.Width(), full_rect.Height(), nullptr,
199 FXDIB_ResampleOptions(), blend_type);
200 }
201
DrawDeviceText(int nChars,const TextCharPos * pCharPos,CFX_Font * pFont,const CFX_Matrix & mtObject2Device,float font_size,uint32_t color)202 bool CGdiPrinterDriver::DrawDeviceText(int nChars,
203 const TextCharPos* pCharPos,
204 CFX_Font* pFont,
205 const CFX_Matrix& mtObject2Device,
206 float font_size,
207 uint32_t color) {
208 #if defined(PDFIUM_PRINT_TEXT_WITH_GDI)
209 if (!g_pdfium_print_text_with_gdi)
210 return false;
211
212 if (nChars < 1 || !pFont || !pFont->IsEmbedded() || !pFont->IsTTFont())
213 return false;
214
215 // Scale factor used to minimize the kerning problems caused by rounding
216 // errors below. Value chosen based on the title of https://crbug.com/18383
217 const double kScaleFactor = 10;
218
219 // Font
220 //
221 // Note that |pFont| has the actual font to render with embedded within, but
222 // but unfortunately AddFontMemResourceEx() does not seem to cooperate.
223 // Loading font data to memory seems to work, but then enumerating the fonts
224 // fails to find it. This requires more investigation. In the meanwhile,
225 // assume the printing is happening on the machine that generated the PDF, so
226 // the embedded font, if not a web font, is available through GDI anyway.
227 // TODO(thestig): Figure out why AddFontMemResourceEx() does not work.
228 // Generalize this method to work for all PDFs with embedded fonts.
229 // In sandboxed environments, font loading may not work at all, so this may be
230 // the best possible effort.
231 LOGFONT lf = {};
232 lf.lfHeight = -font_size * kScaleFactor;
233 lf.lfWeight = pFont->IsBold() ? FW_BOLD : FW_NORMAL;
234 lf.lfItalic = pFont->IsItalic();
235 lf.lfCharSet = DEFAULT_CHARSET;
236
237 const WideString wsName =
238 WideString::FromUTF8(pFont->GetFaceName().AsStringView());
239 size_t iNameLen =
240 std::min(wsName.GetLength(), static_cast<size_t>(LF_FACESIZE - 1));
241 memcpy(lf.lfFaceName, wsName.c_str(), sizeof(lf.lfFaceName[0]) * iNameLen);
242 lf.lfFaceName[iNameLen] = 0;
243
244 HFONT hFont = CreateFontIndirect(&lf);
245 if (!hFont)
246 return false;
247
248 ScopedState state(m_hDC, hFont);
249 size_t nTextMetricSize = GetOutlineTextMetrics(m_hDC, 0, nullptr);
250 if (nTextMetricSize == 0) {
251 // Give up and fail if there is no way to get the font to try again.
252 if (!g_pdfium_typeface_accessible_func)
253 return false;
254
255 // Try to get the font. Any letter will do.
256 g_pdfium_typeface_accessible_func(&lf, L"A", 1);
257 nTextMetricSize = GetOutlineTextMetrics(m_hDC, 0, nullptr);
258 if (nTextMetricSize == 0)
259 return false;
260 }
261
262 std::vector<BYTE> buf(nTextMetricSize);
263 OUTLINETEXTMETRIC* pTextMetric =
264 reinterpret_cast<OUTLINETEXTMETRIC*>(buf.data());
265 if (GetOutlineTextMetrics(m_hDC, nTextMetricSize, pTextMetric) == 0)
266 return false;
267
268 // If the selected font is not the requested font, then bail out. This can
269 // happen with web fonts, for example.
270 wchar_t* wsSelectedName = reinterpret_cast<wchar_t*>(
271 buf.data() + reinterpret_cast<size_t>(pTextMetric->otmpFaceName));
272 if (wsName != wsSelectedName)
273 return false;
274
275 // Transforms
276 SetGraphicsMode(m_hDC, GM_ADVANCED);
277 XFORM xform;
278 xform.eM11 = mtObject2Device.a / kScaleFactor;
279 xform.eM12 = mtObject2Device.b / kScaleFactor;
280 xform.eM21 = -mtObject2Device.c / kScaleFactor;
281 xform.eM22 = -mtObject2Device.d / kScaleFactor;
282 xform.eDx = mtObject2Device.e;
283 xform.eDy = mtObject2Device.f;
284 ModifyWorldTransform(m_hDC, &xform, MWT_LEFTMULTIPLY);
285
286 // Color
287 FX_COLORREF colorref = ArgbToColorRef(color);
288 SetTextColor(m_hDC, colorref);
289 SetBkMode(m_hDC, TRANSPARENT);
290
291 // Text
292 WideString wsText;
293 std::vector<INT> spacing(nChars);
294 float fPreviousOriginX = 0;
295 for (int i = 0; i < nChars; ++i) {
296 // Only works with PDFs from Skia's PDF generator. Cannot handle arbitrary
297 // values from PDFs.
298 const TextCharPos& charpos = pCharPos[i];
299 ASSERT(charpos.m_AdjustMatrix[0] == 0);
300 ASSERT(charpos.m_AdjustMatrix[1] == 0);
301 ASSERT(charpos.m_AdjustMatrix[2] == 0);
302 ASSERT(charpos.m_AdjustMatrix[3] == 0);
303 ASSERT(charpos.m_Origin.y == 0);
304
305 // Round the spacing to the nearest integer, but keep track of the rounding
306 // error for calculating the next spacing value.
307 float fOriginX = charpos.m_Origin.x * kScaleFactor;
308 float fPixelSpacing = fOriginX - fPreviousOriginX;
309 spacing[i] = FXSYS_roundf(fPixelSpacing);
310 fPreviousOriginX = fOriginX - (fPixelSpacing - spacing[i]);
311
312 wsText += charpos.m_GlyphIndex;
313 }
314
315 // Draw
316 SetTextAlign(m_hDC, TA_LEFT | TA_BASELINE);
317 if (ExtTextOutW(m_hDC, 0, 0, ETO_GLYPH_INDEX, nullptr, wsText.c_str(), nChars,
318 nChars > 1 ? &spacing[1] : nullptr)) {
319 return true;
320 }
321
322 // Give up and fail if there is no way to get the font to try again.
323 if (!g_pdfium_typeface_accessible_func)
324 return false;
325
326 // Try to get the font and draw again.
327 g_pdfium_typeface_accessible_func(&lf, wsText.c_str(), nChars);
328 return !!ExtTextOutW(m_hDC, 0, 0, ETO_GLYPH_INDEX, nullptr, wsText.c_str(),
329 nChars, nChars > 1 ? &spacing[1] : nullptr);
330 #else
331 return false;
332 #endif
333 }
334
CPSPrinterDriver(HDC hDC,WindowsPrintMode mode,bool bCmykOutput,const EncoderIface * pEncoderIface)335 CPSPrinterDriver::CPSPrinterDriver(HDC hDC,
336 WindowsPrintMode mode,
337 bool bCmykOutput,
338 const EncoderIface* pEncoderIface)
339 : m_hDC(hDC), m_bCmykOutput(bCmykOutput), m_PSRenderer(pEncoderIface) {
340 // |mode| should be PostScript.
341 ASSERT(mode == WindowsPrintMode::kModePostScript2 ||
342 mode == WindowsPrintMode::kModePostScript3 ||
343 mode == WindowsPrintMode::kModePostScript2PassThrough ||
344 mode == WindowsPrintMode::kModePostScript3PassThrough);
345 int pslevel = (mode == WindowsPrintMode::kModePostScript2 ||
346 mode == WindowsPrintMode::kModePostScript2PassThrough)
347 ? 2
348 : 3;
349 CPSOutput::OutputMode output_mode =
350 (mode == WindowsPrintMode::kModePostScript2 ||
351 mode == WindowsPrintMode::kModePostScript3)
352 ? CPSOutput::OutputMode::kGdiComment
353 : CPSOutput::OutputMode::kExtEscape;
354
355 m_HorzSize = ::GetDeviceCaps(m_hDC, HORZSIZE);
356 m_VertSize = ::GetDeviceCaps(m_hDC, VERTSIZE);
357 m_Width = ::GetDeviceCaps(m_hDC, HORZRES);
358 m_Height = ::GetDeviceCaps(m_hDC, VERTRES);
359 m_nBitsPerPixel = ::GetDeviceCaps(m_hDC, BITSPIXEL);
360
361 m_PSRenderer.Init(pdfium::MakeRetain<CPSOutput>(m_hDC, output_mode), pslevel,
362 m_Width, m_Height, bCmykOutput);
363 HRGN hRgn = ::CreateRectRgn(0, 0, 1, 1);
364 if (::GetClipRgn(m_hDC, hRgn) == 1) {
365 DWORD dwCount = ::GetRegionData(hRgn, 0, nullptr);
366 if (dwCount) {
367 std::vector<uint8_t> buffer(dwCount);
368 RGNDATA* pData = reinterpret_cast<RGNDATA*>(buffer.data());
369 if (::GetRegionData(hRgn, dwCount, pData)) {
370 CFX_PathData path;
371 for (uint32_t i = 0; i < pData->rdh.nCount; i++) {
372 RECT* pRect =
373 reinterpret_cast<RECT*>(pData->Buffer + pData->rdh.nRgnSize * i);
374 path.AppendRect(static_cast<float>(pRect->left),
375 static_cast<float>(pRect->bottom),
376 static_cast<float>(pRect->right),
377 static_cast<float>(pRect->top));
378 }
379 m_PSRenderer.SetClip_PathFill(&path, nullptr, FXFILL_WINDING);
380 }
381 }
382 }
383 ::DeleteObject(hRgn);
384 }
385
~CPSPrinterDriver()386 CPSPrinterDriver::~CPSPrinterDriver() {
387 EndRendering();
388 }
389
GetDeviceType() const390 DeviceType CPSPrinterDriver::GetDeviceType() const {
391 return DeviceType::kPrinter;
392 }
393
GetDeviceCaps(int caps_id) const394 int CPSPrinterDriver::GetDeviceCaps(int caps_id) const {
395 switch (caps_id) {
396 case FXDC_PIXEL_WIDTH:
397 return m_Width;
398 case FXDC_PIXEL_HEIGHT:
399 return m_Height;
400 case FXDC_BITS_PIXEL:
401 return m_nBitsPerPixel;
402 case FXDC_RENDER_CAPS:
403 return m_bCmykOutput ? FXRC_BIT_MASK | FXRC_CMYK_OUTPUT : FXRC_BIT_MASK;
404 case FXDC_HORZ_SIZE:
405 return m_HorzSize;
406 case FXDC_VERT_SIZE:
407 return m_VertSize;
408 default:
409 NOTREACHED();
410 return 0;
411 }
412 }
413
StartRendering()414 bool CPSPrinterDriver::StartRendering() {
415 return m_PSRenderer.StartRendering();
416 }
417
EndRendering()418 void CPSPrinterDriver::EndRendering() {
419 m_PSRenderer.EndRendering();
420 }
421
SaveState()422 void CPSPrinterDriver::SaveState() {
423 m_PSRenderer.SaveState();
424 }
425
RestoreState(bool bKeepSaved)426 void CPSPrinterDriver::RestoreState(bool bKeepSaved) {
427 m_PSRenderer.RestoreState(bKeepSaved);
428 }
429
SetClip_PathFill(const CFX_PathData * pPathData,const CFX_Matrix * pObject2Device,int fill_mode)430 bool CPSPrinterDriver::SetClip_PathFill(const CFX_PathData* pPathData,
431 const CFX_Matrix* pObject2Device,
432 int fill_mode) {
433 m_PSRenderer.SetClip_PathFill(pPathData, pObject2Device, fill_mode);
434 return true;
435 }
436
SetClip_PathStroke(const CFX_PathData * pPathData,const CFX_Matrix * pObject2Device,const CFX_GraphStateData * pGraphState)437 bool CPSPrinterDriver::SetClip_PathStroke(
438 const CFX_PathData* pPathData,
439 const CFX_Matrix* pObject2Device,
440 const CFX_GraphStateData* pGraphState) {
441 m_PSRenderer.SetClip_PathStroke(pPathData, pObject2Device, pGraphState);
442 return true;
443 }
444
DrawPath(const CFX_PathData * pPathData,const CFX_Matrix * pObject2Device,const CFX_GraphStateData * pGraphState,FX_ARGB fill_color,FX_ARGB stroke_color,int fill_mode,BlendMode blend_type)445 bool CPSPrinterDriver::DrawPath(const CFX_PathData* pPathData,
446 const CFX_Matrix* pObject2Device,
447 const CFX_GraphStateData* pGraphState,
448 FX_ARGB fill_color,
449 FX_ARGB stroke_color,
450 int fill_mode,
451 BlendMode blend_type) {
452 if (blend_type != BlendMode::kNormal)
453 return false;
454 return m_PSRenderer.DrawPath(pPathData, pObject2Device, pGraphState,
455 fill_color, stroke_color, fill_mode & 3);
456 }
457
GetClipBox(FX_RECT * pRect)458 bool CPSPrinterDriver::GetClipBox(FX_RECT* pRect) {
459 *pRect = m_PSRenderer.GetClipBox();
460 return true;
461 }
462
SetDIBits(const RetainPtr<CFX_DIBBase> & pBitmap,uint32_t color,const FX_RECT & src_rect,int left,int top,BlendMode blend_type)463 bool CPSPrinterDriver::SetDIBits(const RetainPtr<CFX_DIBBase>& pBitmap,
464 uint32_t color,
465 const FX_RECT& src_rect,
466 int left,
467 int top,
468 BlendMode blend_type) {
469 if (blend_type != BlendMode::kNormal)
470 return false;
471 return m_PSRenderer.SetDIBits(pBitmap, color, left, top);
472 }
473
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)474 bool CPSPrinterDriver::StretchDIBits(const RetainPtr<CFX_DIBBase>& pBitmap,
475 uint32_t color,
476 int dest_left,
477 int dest_top,
478 int dest_width,
479 int dest_height,
480 const FX_RECT* pClipRect,
481 const FXDIB_ResampleOptions& options,
482 BlendMode blend_type) {
483 if (blend_type != BlendMode::kNormal)
484 return false;
485 return m_PSRenderer.StretchDIBits(pBitmap, color, dest_left, dest_top,
486 dest_width, dest_height, options);
487 }
488
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)489 bool CPSPrinterDriver::StartDIBits(const RetainPtr<CFX_DIBBase>& pBitmap,
490 int bitmap_alpha,
491 uint32_t color,
492 const CFX_Matrix& matrix,
493 const FXDIB_ResampleOptions& options,
494 std::unique_ptr<CFX_ImageRenderer>* handle,
495 BlendMode blend_type) {
496 if (blend_type != BlendMode::kNormal)
497 return false;
498
499 if (bitmap_alpha < 255)
500 return false;
501
502 *handle = nullptr;
503 return m_PSRenderer.DrawDIBits(pBitmap, color, matrix, options);
504 }
505
DrawDeviceText(int nChars,const TextCharPos * pCharPos,CFX_Font * pFont,const CFX_Matrix & mtObject2Device,float font_size,uint32_t color)506 bool CPSPrinterDriver::DrawDeviceText(int nChars,
507 const TextCharPos* pCharPos,
508 CFX_Font* pFont,
509 const CFX_Matrix& mtObject2Device,
510 float font_size,
511 uint32_t color) {
512 return m_PSRenderer.DrawText(nChars, pCharPos, pFont, mtObject2Device,
513 font_size, color);
514 }
515
CTextOnlyPrinterDriver(HDC hDC)516 CTextOnlyPrinterDriver::CTextOnlyPrinterDriver(HDC hDC)
517 : m_hDC(hDC),
518 m_Width(INT_MAX),
519 m_Height(INT_MAX),
520 m_HorzSize(INT_MAX),
521 m_VertSize(INT_MAX),
522 m_OriginY(0.0f),
523 m_SetOrigin(false) {
524 m_nBitsPerPixel = ::GetDeviceCaps(m_hDC, BITSPIXEL);
525 }
526
~CTextOnlyPrinterDriver()527 CTextOnlyPrinterDriver::~CTextOnlyPrinterDriver() {
528 EndRendering();
529 }
530
GetDeviceType() const531 DeviceType CTextOnlyPrinterDriver::GetDeviceType() const {
532 return DeviceType::kPrinter;
533 }
534
GetDeviceCaps(int caps_id) const535 int CTextOnlyPrinterDriver::GetDeviceCaps(int caps_id) const {
536 switch (caps_id) {
537 case FXDC_PIXEL_WIDTH:
538 return m_Width;
539 case FXDC_PIXEL_HEIGHT:
540 return m_Height;
541 case FXDC_BITS_PIXEL:
542 return m_nBitsPerPixel;
543 case FXDC_RENDER_CAPS:
544 return 0;
545 case FXDC_HORZ_SIZE:
546 return m_HorzSize;
547 case FXDC_VERT_SIZE:
548 return m_VertSize;
549 default:
550 NOTREACHED();
551 return 0;
552 }
553 }
554
SetClip_PathFill(const CFX_PathData * pPathData,const CFX_Matrix * pObject2Device,int fill_mode)555 bool CTextOnlyPrinterDriver::SetClip_PathFill(const CFX_PathData* pPathData,
556 const CFX_Matrix* pObject2Device,
557 int fill_mode) {
558 return true;
559 }
560
SetClip_PathStroke(const CFX_PathData * pPathData,const CFX_Matrix * pObject2Device,const CFX_GraphStateData * pGraphState)561 bool CTextOnlyPrinterDriver::SetClip_PathStroke(
562 const CFX_PathData* pPathData,
563 const CFX_Matrix* pObject2Device,
564 const CFX_GraphStateData* pGraphState) {
565 return false;
566 }
567
DrawPath(const CFX_PathData * pPathData,const CFX_Matrix * pObject2Device,const CFX_GraphStateData * pGraphState,uint32_t fill_color,uint32_t stroke_color,int fill_mode,BlendMode blend_type)568 bool CTextOnlyPrinterDriver::DrawPath(const CFX_PathData* pPathData,
569 const CFX_Matrix* pObject2Device,
570 const CFX_GraphStateData* pGraphState,
571 uint32_t fill_color,
572 uint32_t stroke_color,
573 int fill_mode,
574 BlendMode blend_type) {
575 return false;
576 }
577
SetDIBits(const RetainPtr<CFX_DIBBase> & pBitmap,uint32_t color,const FX_RECT & src_rect,int left,int top,BlendMode blend_type)578 bool CTextOnlyPrinterDriver::SetDIBits(const RetainPtr<CFX_DIBBase>& pBitmap,
579 uint32_t color,
580 const FX_RECT& src_rect,
581 int left,
582 int top,
583 BlendMode blend_type) {
584 return false;
585 }
586
GetClipBox(FX_RECT * pRect)587 bool CTextOnlyPrinterDriver::GetClipBox(FX_RECT* pRect) {
588 pRect->left = 0;
589 pRect->right = m_Width;
590 pRect->top = 0;
591 pRect->bottom = m_Height;
592 return true;
593 }
594
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)595 bool CTextOnlyPrinterDriver::StretchDIBits(
596 const RetainPtr<CFX_DIBBase>& pBitmap,
597 uint32_t color,
598 int dest_left,
599 int dest_top,
600 int dest_width,
601 int dest_height,
602 const FX_RECT* pClipRect,
603 const FXDIB_ResampleOptions& options,
604 BlendMode blend_type) {
605 return false;
606 }
607
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)608 bool CTextOnlyPrinterDriver::StartDIBits(
609 const RetainPtr<CFX_DIBBase>& pBitmap,
610 int bitmap_alpha,
611 uint32_t color,
612 const CFX_Matrix& matrix,
613 const FXDIB_ResampleOptions& options,
614 std::unique_ptr<CFX_ImageRenderer>* handle,
615 BlendMode blend_type) {
616 return false;
617 }
618
DrawDeviceText(int nChars,const TextCharPos * pCharPos,CFX_Font * pFont,const CFX_Matrix & mtObject2Device,float font_size,uint32_t color)619 bool CTextOnlyPrinterDriver::DrawDeviceText(int nChars,
620 const TextCharPos* pCharPos,
621 CFX_Font* pFont,
622 const CFX_Matrix& mtObject2Device,
623 float font_size,
624 uint32_t color) {
625 if (g_pdfium_print_mode != 1)
626 return false;
627 if (nChars < 1 || !pFont || !pFont->IsEmbedded() || !pFont->IsTTFont())
628 return false;
629
630 // Scale factor used to minimize the kerning problems caused by rounding
631 // errors below. Value chosen based on the title of https://crbug.com/18383
632 const double kScaleFactor = 10;
633
634 // Detect new lines and add clrf characters (since this is Windows only).
635 // These characters are removed by SkPDF, but the new line information is
636 // preserved in the text location. clrf characters seem to be ignored by
637 // label printers that use this driver.
638 WideString wsText;
639 size_t len = nChars;
640 float fOffsetY = mtObject2Device.f * kScaleFactor;
641 if (m_SetOrigin && FXSYS_roundf(m_OriginY) != FXSYS_roundf(fOffsetY)) {
642 wsText += L"\r\n";
643 len += 2;
644 }
645 wsText.Reserve(len);
646 m_OriginY = fOffsetY;
647 m_SetOrigin = true;
648
649 // Text
650 for (int i = 0; i < nChars; ++i) {
651 // Only works with PDFs from Skia's PDF generator. Cannot handle arbitrary
652 // values from PDFs.
653 const TextCharPos& charpos = pCharPos[i];
654 ASSERT(charpos.m_AdjustMatrix[0] == 0);
655 ASSERT(charpos.m_AdjustMatrix[1] == 0);
656 ASSERT(charpos.m_AdjustMatrix[2] == 0);
657 ASSERT(charpos.m_AdjustMatrix[3] == 0);
658 ASSERT(charpos.m_Origin.y == 0);
659
660 wsText += charpos.m_Unicode;
661 }
662 ByteString text = wsText.ToDefANSI();
663 auto text_span = text.span();
664 while (!text_span.empty()) {
665 uint8_t buffer[1026];
666 size_t send_len = std::min<size_t>(text_span.size(), 1024);
667 *(reinterpret_cast<uint16_t*>(buffer)) = static_cast<uint16_t>(send_len);
668 memcpy(buffer + 2, text_span.data(), send_len);
669 ::GdiComment(m_hDC, send_len + 2, buffer);
670 text_span = text_span.subspan(send_len);
671 }
672 return true;
673 }
674