• 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_windowsdevice.h"
15 #include "core/fxge/dib/dib_int.h"
16 #include "core/fxge/fx_freetype.h"
17 #include "core/fxge/ge/fx_text_int.h"
18 #include "core/fxge/win32/cpsoutput.h"
19 #include "core/fxge/win32/win32_int.h"
20 #include "third_party/base/ptr_util.h"
21 
22 #if defined(PDFIUM_PRINT_TEXT_WITH_GDI)
23 namespace {
24 
25 class ScopedState {
26  public:
ScopedState(HDC hDC,HFONT hFont)27   ScopedState(HDC hDC, HFONT hFont) : m_hDC(hDC) {
28     m_iState = SaveDC(m_hDC);
29     m_hFont = SelectObject(m_hDC, hFont);
30   }
31 
~ScopedState()32   ~ScopedState() {
33     HGDIOBJ hFont = SelectObject(m_hDC, m_hFont);
34     DeleteObject(hFont);
35     RestoreDC(m_hDC, m_iState);
36   }
37 
38  private:
39   HDC m_hDC;
40   HGDIOBJ m_hFont;
41   int m_iState;
42 
43   ScopedState(const ScopedState&) = delete;
44   void operator=(const ScopedState&) = delete;
45 };
46 
47 }  // namespace
48 
49 bool g_pdfium_print_text_with_gdi = false;
50 
51 PDFiumEnsureTypefaceCharactersAccessible g_pdfium_typeface_accessible_func =
52     nullptr;
53 #endif
54 
CGdiPrinterDriver(HDC hDC)55 CGdiPrinterDriver::CGdiPrinterDriver(HDC hDC)
56     : CGdiDeviceDriver(hDC, FXDC_PRINTER),
57       m_HorzSize(::GetDeviceCaps(m_hDC, HORZSIZE)),
58       m_VertSize(::GetDeviceCaps(m_hDC, VERTSIZE)) {}
59 
~CGdiPrinterDriver()60 CGdiPrinterDriver::~CGdiPrinterDriver() {}
61 
GetDeviceCaps(int caps_id) const62 int CGdiPrinterDriver::GetDeviceCaps(int caps_id) const {
63   if (caps_id == FXDC_HORZ_SIZE)
64     return m_HorzSize;
65   if (caps_id == FXDC_VERT_SIZE)
66     return m_VertSize;
67   return CGdiDeviceDriver::GetDeviceCaps(caps_id);
68 }
69 
SetDIBits(const CFX_DIBSource * pSource,uint32_t color,const FX_RECT * pSrcRect,int left,int top,int blend_type)70 bool CGdiPrinterDriver::SetDIBits(const CFX_DIBSource* pSource,
71                                   uint32_t color,
72                                   const FX_RECT* pSrcRect,
73                                   int left,
74                                   int top,
75                                   int blend_type) {
76   if (pSource->IsAlphaMask()) {
77     FX_RECT clip_rect(left, top, left + pSrcRect->Width(),
78                       top + pSrcRect->Height());
79     return StretchDIBits(pSource, color, left - pSrcRect->left,
80                          top - pSrcRect->top, pSource->GetWidth(),
81                          pSource->GetHeight(), &clip_rect, 0,
82                          FXDIB_BLEND_NORMAL);
83   }
84   ASSERT(pSource && !pSource->IsAlphaMask() && pSrcRect);
85   ASSERT(blend_type == FXDIB_BLEND_NORMAL);
86   if (pSource->HasAlpha())
87     return false;
88 
89   CFX_DIBExtractor temp(pSource);
90   CFX_DIBitmap* pBitmap = temp.GetBitmap();
91   if (!pBitmap)
92     return false;
93 
94   return GDI_SetDIBits(pBitmap, pSrcRect, left, top);
95 }
96 
StretchDIBits(const 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)97 bool CGdiPrinterDriver::StretchDIBits(const CFX_DIBSource* pSource,
98                                       uint32_t color,
99                                       int dest_left,
100                                       int dest_top,
101                                       int dest_width,
102                                       int dest_height,
103                                       const FX_RECT* pClipRect,
104                                       uint32_t flags,
105                                       int blend_type) {
106   if (pSource->IsAlphaMask()) {
107     int alpha = FXARGB_A(color);
108     if (pSource->GetBPP() != 1 || alpha != 255)
109       return false;
110 
111     if (dest_width < 0 || dest_height < 0) {
112       std::unique_ptr<CFX_DIBitmap> pFlipped =
113           pSource->FlipImage(dest_width < 0, dest_height < 0);
114       if (!pFlipped)
115         return false;
116 
117       if (dest_width < 0)
118         dest_left += dest_width;
119       if (dest_height < 0)
120         dest_top += dest_height;
121 
122       return GDI_StretchBitMask(pFlipped.get(), dest_left, dest_top,
123                                 abs(dest_width), abs(dest_height), color,
124                                 flags);
125     }
126 
127     CFX_DIBExtractor temp(pSource);
128     CFX_DIBitmap* pBitmap = temp.GetBitmap();
129     if (!pBitmap)
130       return false;
131     return GDI_StretchBitMask(pBitmap, dest_left, dest_top, dest_width,
132                               dest_height, color, flags);
133   }
134 
135   if (pSource->HasAlpha())
136     return false;
137 
138   if (dest_width < 0 || dest_height < 0) {
139     std::unique_ptr<CFX_DIBitmap> pFlipped =
140         pSource->FlipImage(dest_width < 0, dest_height < 0);
141     if (!pFlipped)
142       return false;
143 
144     if (dest_width < 0)
145       dest_left += dest_width;
146     if (dest_height < 0)
147       dest_top += dest_height;
148 
149     return GDI_StretchDIBits(pFlipped.get(), dest_left, dest_top,
150                              abs(dest_width), abs(dest_height), flags);
151   }
152 
153   CFX_DIBExtractor temp(pSource);
154   CFX_DIBitmap* pBitmap = temp.GetBitmap();
155   if (!pBitmap)
156     return false;
157   return GDI_StretchDIBits(pBitmap, dest_left, dest_top, dest_width,
158                            dest_height, flags);
159 }
160 
StartDIBits(const CFX_DIBSource * pSource,int bitmap_alpha,uint32_t color,const CFX_Matrix * pMatrix,uint32_t render_flags,void * & handle,int blend_type)161 bool CGdiPrinterDriver::StartDIBits(const CFX_DIBSource* pSource,
162                                     int bitmap_alpha,
163                                     uint32_t color,
164                                     const CFX_Matrix* pMatrix,
165                                     uint32_t render_flags,
166                                     void*& handle,
167                                     int blend_type) {
168   if (bitmap_alpha < 255 || pSource->HasAlpha() ||
169       (pSource->IsAlphaMask() && (pSource->GetBPP() != 1))) {
170     return false;
171   }
172   CFX_FloatRect unit_rect = pMatrix->GetUnitRect();
173   FX_RECT full_rect = unit_rect.GetOuterRect();
174   if (FXSYS_fabs(pMatrix->b) < 0.5f && pMatrix->a != 0 &&
175       FXSYS_fabs(pMatrix->c) < 0.5f && pMatrix->d != 0) {
176     bool bFlipX = pMatrix->a < 0;
177     bool bFlipY = pMatrix->d > 0;
178     return StretchDIBits(pSource, color,
179                          bFlipX ? full_rect.right : full_rect.left,
180                          bFlipY ? full_rect.bottom : full_rect.top,
181                          bFlipX ? -full_rect.Width() : full_rect.Width(),
182                          bFlipY ? -full_rect.Height() : full_rect.Height(),
183                          nullptr, 0, blend_type);
184   }
185   if (FXSYS_fabs(pMatrix->a) >= 0.5f || FXSYS_fabs(pMatrix->d) >= 0.5f)
186     return false;
187 
188   std::unique_ptr<CFX_DIBitmap> pTransformed =
189       pSource->SwapXY(pMatrix->c > 0, pMatrix->b < 0);
190   if (!pTransformed)
191     return false;
192 
193   return StretchDIBits(pTransformed.get(), color, full_rect.left, full_rect.top,
194                        full_rect.Width(), full_rect.Height(), nullptr, 0,
195                        blend_type);
196 }
197 
DrawDeviceText(int nChars,const FXTEXT_CHARPOS * pCharPos,CFX_Font * pFont,const CFX_Matrix * pObject2Device,FX_FLOAT font_size,uint32_t color)198 bool CGdiPrinterDriver::DrawDeviceText(int nChars,
199                                        const FXTEXT_CHARPOS* pCharPos,
200                                        CFX_Font* pFont,
201                                        const CFX_Matrix* pObject2Device,
202                                        FX_FLOAT font_size,
203                                        uint32_t color) {
204 #if defined(PDFIUM_PRINT_TEXT_WITH_GDI)
205   if (!g_pdfium_print_text_with_gdi)
206     return false;
207 
208   if (nChars < 1 || !pFont || !pFont->IsEmbedded() || !pFont->IsTTFont())
209     return false;
210 
211   // Scale factor used to minimize the kerning problems caused by rounding
212   // errors below. Value choosen based on the title of https://crbug.com/18383
213   const double kScaleFactor = 10;
214 
215   // Font
216   //
217   // Note that |pFont| has the actual font to render with embedded within, but
218   // but unfortunately AddFontMemResourceEx() does not seem to cooperate.
219   // Loading font data to memory seems to work, but then enumerating the fonts
220   // fails to find it. This requires more investigation. In the meanwhile,
221   // assume the printing is happening on the machine that generated the PDF, so
222   // the embedded font, if not a web font, is available through GDI anyway.
223   // TODO(thestig): Figure out why AddFontMemResourceEx() does not work.
224   // Generalize this method to work for all PDFs with embedded fonts.
225   // In sandboxed environments, font loading may not work at all, so this may be
226   // the best possible effort.
227   LOGFONT lf = {};
228   lf.lfHeight = -font_size * kScaleFactor;
229   lf.lfWeight = pFont->IsBold() ? FW_BOLD : FW_NORMAL;
230   lf.lfItalic = pFont->IsItalic();
231   lf.lfCharSet = DEFAULT_CHARSET;
232 
233   const CFX_WideString wsName = pFont->GetFaceName().UTF8Decode();
234   int iNameLen = std::min(wsName.GetLength(), LF_FACESIZE - 1);
235   memcpy(lf.lfFaceName, wsName.c_str(), sizeof(lf.lfFaceName[0]) * iNameLen);
236   lf.lfFaceName[iNameLen] = 0;
237 
238   HFONT hFont = CreateFontIndirect(&lf);
239   if (!hFont)
240     return false;
241 
242   ScopedState state(m_hDC, hFont);
243   size_t nTextMetricSize = GetOutlineTextMetrics(m_hDC, 0, nullptr);
244   if (nTextMetricSize == 0) {
245     // Give up and fail if there is no way to get the font to try again.
246     if (!g_pdfium_typeface_accessible_func)
247       return false;
248 
249     // Try to get the font. Any letter will do.
250     g_pdfium_typeface_accessible_func(&lf, L"A", 1);
251     nTextMetricSize = GetOutlineTextMetrics(m_hDC, 0, nullptr);
252     if (nTextMetricSize == 0)
253       return false;
254   }
255 
256   std::vector<BYTE> buf(nTextMetricSize);
257   OUTLINETEXTMETRIC* pTextMetric =
258       reinterpret_cast<OUTLINETEXTMETRIC*>(buf.data());
259   if (GetOutlineTextMetrics(m_hDC, nTextMetricSize, pTextMetric) == 0)
260     return false;
261 
262   // If the selected font is not the requested font, then bail out. This can
263   // happen with web fonts, for example.
264   wchar_t* wsSelectedName = reinterpret_cast<wchar_t*>(
265       buf.data() + reinterpret_cast<size_t>(pTextMetric->otmpFaceName));
266   if (wsName != wsSelectedName)
267     return false;
268 
269   // Transforms
270   SetGraphicsMode(m_hDC, GM_ADVANCED);
271   XFORM xform;
272   xform.eM11 = pObject2Device->a / kScaleFactor;
273   xform.eM12 = pObject2Device->b / kScaleFactor;
274   xform.eM21 = -pObject2Device->c / kScaleFactor;
275   xform.eM22 = -pObject2Device->d / kScaleFactor;
276   xform.eDx = pObject2Device->e;
277   xform.eDy = pObject2Device->f;
278   ModifyWorldTransform(m_hDC, &xform, MWT_LEFTMULTIPLY);
279 
280   // Color
281   int iUnusedAlpha;
282   FX_COLORREF rgb;
283   ArgbDecode(color, iUnusedAlpha, rgb);
284   SetTextColor(m_hDC, rgb);
285   SetBkMode(m_hDC, TRANSPARENT);
286 
287   // Text
288   CFX_WideString wsText;
289   std::vector<INT> spacing(nChars);
290   FX_FLOAT fPreviousOriginX = 0;
291   for (int i = 0; i < nChars; ++i) {
292     // Only works with PDFs from Skia's PDF generator. Cannot handle arbitrary
293     // values from PDFs.
294     const FXTEXT_CHARPOS& charpos = pCharPos[i];
295     ASSERT(charpos.m_AdjustMatrix[0] == 0);
296     ASSERT(charpos.m_AdjustMatrix[1] == 0);
297     ASSERT(charpos.m_AdjustMatrix[2] == 0);
298     ASSERT(charpos.m_AdjustMatrix[3] == 0);
299     ASSERT(charpos.m_Origin.y == 0);
300 
301     // Round the spacing to the nearest integer, but keep track of the rounding
302     // error for calculating the next spacing value.
303     FX_FLOAT fOriginX = charpos.m_Origin.x * kScaleFactor;
304     FX_FLOAT fPixelSpacing = fOriginX - fPreviousOriginX;
305     spacing[i] = FXSYS_round(fPixelSpacing);
306     fPreviousOriginX = fOriginX - (fPixelSpacing - spacing[i]);
307 
308     wsText += charpos.m_GlyphIndex;
309   }
310 
311   // Draw
312   SetTextAlign(m_hDC, TA_LEFT | TA_BASELINE);
313   if (ExtTextOutW(m_hDC, 0, 0, ETO_GLYPH_INDEX, nullptr, wsText.c_str(), nChars,
314                   nChars > 1 ? &spacing[1] : nullptr)) {
315     return true;
316   }
317 
318   // Give up and fail if there is no way to get the font to try again.
319   if (!g_pdfium_typeface_accessible_func)
320     return false;
321 
322   // Try to get the font and draw again.
323   g_pdfium_typeface_accessible_func(&lf, wsText.c_str(), nChars);
324   return !!ExtTextOutW(m_hDC, 0, 0, ETO_GLYPH_INDEX, nullptr, wsText.c_str(),
325                        nChars, nChars > 1 ? &spacing[1] : nullptr);
326 #else
327   return false;
328 #endif
329 }
330 
CPSPrinterDriver(HDC hDC,int pslevel,bool bCmykOutput)331 CPSPrinterDriver::CPSPrinterDriver(HDC hDC, int pslevel, bool bCmykOutput)
332     : m_hDC(hDC), m_bCmykOutput(bCmykOutput) {
333   m_HorzSize = ::GetDeviceCaps(m_hDC, HORZSIZE);
334   m_VertSize = ::GetDeviceCaps(m_hDC, VERTSIZE);
335   m_Width = ::GetDeviceCaps(m_hDC, HORZRES);
336   m_Height = ::GetDeviceCaps(m_hDC, VERTRES);
337   m_nBitsPerPixel = ::GetDeviceCaps(m_hDC, BITSPIXEL);
338   m_pPSOutput = pdfium::MakeUnique<CPSOutput>(m_hDC);
339   m_PSRenderer.Init(m_pPSOutput.get(), pslevel, m_Width, m_Height, bCmykOutput);
340   HRGN hRgn = ::CreateRectRgn(0, 0, 1, 1);
341   int ret = ::GetClipRgn(hDC, hRgn);
342   if (ret == 1) {
343     ret = ::GetRegionData(hRgn, 0, NULL);
344     if (ret) {
345       RGNDATA* pData = reinterpret_cast<RGNDATA*>(FX_Alloc(uint8_t, ret));
346       ret = ::GetRegionData(hRgn, ret, pData);
347       if (ret) {
348         CFX_PathData path;
349         for (uint32_t i = 0; i < pData->rdh.nCount; i++) {
350           RECT* pRect =
351               reinterpret_cast<RECT*>(pData->Buffer + pData->rdh.nRgnSize * i);
352           path.AppendRect(static_cast<FX_FLOAT>(pRect->left),
353                           static_cast<FX_FLOAT>(pRect->bottom),
354                           static_cast<FX_FLOAT>(pRect->right),
355                           static_cast<FX_FLOAT>(pRect->top));
356         }
357         m_PSRenderer.SetClip_PathFill(&path, nullptr, FXFILL_WINDING);
358       }
359       FX_Free(pData);
360     }
361   }
362   ::DeleteObject(hRgn);
363 }
364 
~CPSPrinterDriver()365 CPSPrinterDriver::~CPSPrinterDriver() {
366   EndRendering();
367 }
368 
GetDeviceCaps(int caps_id) const369 int CPSPrinterDriver::GetDeviceCaps(int caps_id) const {
370   switch (caps_id) {
371     case FXDC_DEVICE_CLASS:
372       return FXDC_PRINTER;
373     case FXDC_PIXEL_WIDTH:
374       return m_Width;
375     case FXDC_PIXEL_HEIGHT:
376       return m_Height;
377     case FXDC_BITS_PIXEL:
378       return m_nBitsPerPixel;
379     case FXDC_RENDER_CAPS:
380       return m_bCmykOutput ? FXRC_BIT_MASK | FXRC_CMYK_OUTPUT : FXRC_BIT_MASK;
381     case FXDC_HORZ_SIZE:
382       return m_HorzSize;
383     case FXDC_VERT_SIZE:
384       return m_VertSize;
385   }
386   return 0;
387 }
388 
StartRendering()389 bool CPSPrinterDriver::StartRendering() {
390   return m_PSRenderer.StartRendering();
391 }
392 
EndRendering()393 void CPSPrinterDriver::EndRendering() {
394   m_PSRenderer.EndRendering();
395 }
396 
SaveState()397 void CPSPrinterDriver::SaveState() {
398   m_PSRenderer.SaveState();
399 }
400 
RestoreState(bool bKeepSaved)401 void CPSPrinterDriver::RestoreState(bool bKeepSaved) {
402   m_PSRenderer.RestoreState(bKeepSaved);
403 }
404 
SetClip_PathFill(const CFX_PathData * pPathData,const CFX_Matrix * pObject2Device,int fill_mode)405 bool CPSPrinterDriver::SetClip_PathFill(const CFX_PathData* pPathData,
406                                         const CFX_Matrix* pObject2Device,
407                                         int fill_mode) {
408   m_PSRenderer.SetClip_PathFill(pPathData, pObject2Device, fill_mode);
409   return true;
410 }
411 
SetClip_PathStroke(const CFX_PathData * pPathData,const CFX_Matrix * pObject2Device,const CFX_GraphStateData * pGraphState)412 bool CPSPrinterDriver::SetClip_PathStroke(
413     const CFX_PathData* pPathData,
414     const CFX_Matrix* pObject2Device,
415     const CFX_GraphStateData* pGraphState) {
416   m_PSRenderer.SetClip_PathStroke(pPathData, pObject2Device, pGraphState);
417   return true;
418 }
419 
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)420 bool CPSPrinterDriver::DrawPath(const CFX_PathData* pPathData,
421                                 const CFX_Matrix* pObject2Device,
422                                 const CFX_GraphStateData* pGraphState,
423                                 FX_ARGB fill_color,
424                                 FX_ARGB stroke_color,
425                                 int fill_mode,
426                                 int blend_type) {
427   if (blend_type != FXDIB_BLEND_NORMAL) {
428     return false;
429   }
430   return m_PSRenderer.DrawPath(pPathData, pObject2Device, pGraphState,
431                                fill_color, stroke_color, fill_mode & 3);
432 }
433 
GetClipBox(FX_RECT * pRect)434 bool CPSPrinterDriver::GetClipBox(FX_RECT* pRect) {
435   *pRect = m_PSRenderer.GetClipBox();
436   return true;
437 }
438 
SetDIBits(const CFX_DIBSource * pBitmap,uint32_t color,const FX_RECT * pSrcRect,int left,int top,int blend_type)439 bool CPSPrinterDriver::SetDIBits(const CFX_DIBSource* pBitmap,
440                                  uint32_t color,
441                                  const FX_RECT* pSrcRect,
442                                  int left,
443                                  int top,
444                                  int blend_type) {
445   if (blend_type != FXDIB_BLEND_NORMAL)
446     return false;
447   return m_PSRenderer.SetDIBits(pBitmap, color, left, top);
448 }
449 
StretchDIBits(const 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)450 bool CPSPrinterDriver::StretchDIBits(const CFX_DIBSource* pBitmap,
451                                      uint32_t color,
452                                      int dest_left,
453                                      int dest_top,
454                                      int dest_width,
455                                      int dest_height,
456                                      const FX_RECT* pClipRect,
457                                      uint32_t flags,
458                                      int blend_type) {
459   if (blend_type != FXDIB_BLEND_NORMAL)
460     return false;
461   return m_PSRenderer.StretchDIBits(pBitmap, color, dest_left, dest_top,
462                                     dest_width, dest_height, flags);
463 }
464 
StartDIBits(const CFX_DIBSource * pBitmap,int bitmap_alpha,uint32_t color,const CFX_Matrix * pMatrix,uint32_t render_flags,void * & handle,int blend_type)465 bool CPSPrinterDriver::StartDIBits(const CFX_DIBSource* pBitmap,
466                                    int bitmap_alpha,
467                                    uint32_t color,
468                                    const CFX_Matrix* pMatrix,
469                                    uint32_t render_flags,
470                                    void*& handle,
471                                    int blend_type) {
472   if (blend_type != FXDIB_BLEND_NORMAL)
473     return false;
474 
475   if (bitmap_alpha < 255)
476     return false;
477 
478   handle = nullptr;
479   return m_PSRenderer.DrawDIBits(pBitmap, color, pMatrix, render_flags);
480 }
481 
DrawDeviceText(int nChars,const FXTEXT_CHARPOS * pCharPos,CFX_Font * pFont,const CFX_Matrix * pObject2Device,FX_FLOAT font_size,uint32_t color)482 bool CPSPrinterDriver::DrawDeviceText(int nChars,
483                                       const FXTEXT_CHARPOS* pCharPos,
484                                       CFX_Font* pFont,
485                                       const CFX_Matrix* pObject2Device,
486                                       FX_FLOAT font_size,
487                                       uint32_t color) {
488   return m_PSRenderer.DrawText(nChars, pCharPos, pFont, pObject2Device,
489                                font_size, color);
490 }
491 
GetPlatformSurface() const492 void* CPSPrinterDriver::GetPlatformSurface() const {
493   return m_hDC;
494 }
495