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