Home | History | Annotate | Download | only in win32
      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:
     29   ScopedState(HDC hDC, HFONT hFont) : m_hDC(hDC) {
     30     m_iState = SaveDC(m_hDC);
     31     m_hFont = SelectObject(m_hDC, hFont);
     32   }
     33 
     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 
     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 
     62 CGdiPrinterDriver::~CGdiPrinterDriver() {}
     63 
     64 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 
     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 
     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 
    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 
    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 
    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 
    368 CPSPrinterDriver::~CPSPrinterDriver() {
    369   EndRendering();
    370 }
    371 
    372 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 
    392 bool CPSPrinterDriver::StartRendering() {
    393   return m_PSRenderer.StartRendering();
    394 }
    395 
    396 void CPSPrinterDriver::EndRendering() {
    397   m_PSRenderer.EndRendering();
    398 }
    399 
    400 void CPSPrinterDriver::SaveState() {
    401   m_PSRenderer.SaveState();
    402 }
    403 
    404 void CPSPrinterDriver::RestoreState(bool bKeepSaved) {
    405   m_PSRenderer.RestoreState(bKeepSaved);
    406 }
    407 
    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 
    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 
    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 
    437 bool CPSPrinterDriver::GetClipBox(FX_RECT* pRect) {
    438   *pRect = m_PSRenderer.GetClipBox();
    439   return true;
    440 }
    441 
    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 
    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 
    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 
    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 
    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 
    506 CTextOnlyPrinterDriver::~CTextOnlyPrinterDriver() {
    507   EndRendering();
    508 }
    509 
    510 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 
    530 bool CTextOnlyPrinterDriver::SetClip_PathFill(const CFX_PathData* pPathData,
    531                                               const CFX_Matrix* pObject2Device,
    532                                               int fill_mode) {
    533   return true;
    534 }
    535 
    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 
    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 
    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 
    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 
    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 
    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 
    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