• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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