From e8468c43cb3b14f4440456d19cb047150509949d Mon Sep 17 00:00:00 2001 From: rbpotter Date: Tue, 11 Jul 2017 10:04:29 -0700 Subject: Add Windows generic / text only printer driver support. BUG=chromium:734850 Change-Id: Icc0947e2e99e77a36d8963fcf0b6d3deea161d3e Reviewed-on: https://pdfium-review.googlesource.com/7194 Commit-Queue: Rebekah Potter Reviewed-by: Lei Zhang --- core/fpdfapi/render/cpdf_charposlist.cpp | 3 +- core/fxge/cfx_renderdevice.cpp | 3 +- core/fxge/cfx_renderdevice.h | 1 + core/fxge/cfx_windowsrenderdevice.h | 9 +- core/fxge/win32/fx_win32_device.cpp | 20 ++-- core/fxge/win32/fx_win32_print.cpp | 156 +++++++++++++++++++++++++++++++ core/fxge/win32/win32_int.h | 62 ++++++++++++ fpdfsdk/fpdfview.cpp | 17 +++- public/fpdf_edit.h | 5 + public/fpdfview.h | 17 ++-- samples/pdfium_test.cc | 4 +- 11 files changed, 274 insertions(+), 23 deletions(-) diff --git a/core/fpdfapi/render/cpdf_charposlist.cpp b/core/fpdfapi/render/cpdf_charposlist.cpp index 68df46bdad..a87fc3334e 100644 --- a/core/fpdfapi/render/cpdf_charposlist.cpp +++ b/core/fpdfapi/render/cpdf_charposlist.cpp @@ -37,7 +37,8 @@ void CPDF_CharPosList::Load(const std::vector& charCodes, FXTEXT_CHARPOS& charpos = m_pCharPos[m_nChars++]; if (pCIDFont) charpos.m_bFontStyle = true; - + CFX_WideString unicode = pFont->UnicodeFromCharCode(CharCode); + charpos.m_Unicode = !unicode.IsEmpty() ? unicode.GetAt(0) : CharCode; charpos.m_GlyphIndex = pFont->GlyphFromCharCode(CharCode, &bVert); uint32_t GlyphID = charpos.m_GlyphIndex; #if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_ diff --git a/core/fxge/cfx_renderdevice.cpp b/core/fxge/cfx_renderdevice.cpp index 266ae50e78..e1c6a65034 100644 --- a/core/fxge/cfx_renderdevice.cpp +++ b/core/fxge/cfx_renderdevice.cpp @@ -348,7 +348,8 @@ bool ShouldDrawDeviceText(const CFX_Font* pFont, uint32_t text_flags) { } // namespace FXTEXT_CHARPOS::FXTEXT_CHARPOS() - : m_GlyphIndex(0), + : m_Unicode(0), + m_GlyphIndex(0), m_FontCharWidth(0), #if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_ m_ExtGID(0), diff --git a/core/fxge/cfx_renderdevice.h b/core/fxge/cfx_renderdevice.h index f33da57cc9..165b729541 100644 --- a/core/fxge/cfx_renderdevice.h +++ b/core/fxge/cfx_renderdevice.h @@ -71,6 +71,7 @@ class FXTEXT_CHARPOS { float m_AdjustMatrix[4]; CFX_PointF m_Origin; + uint32_t m_Unicode; uint32_t m_GlyphIndex; int32_t m_FontCharWidth; #if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_ diff --git a/core/fxge/cfx_windowsrenderdevice.h b/core/fxge/cfx_windowsrenderdevice.h index 7156dcdc4e..f1e0cbdb7a 100644 --- a/core/fxge/cfx_windowsrenderdevice.h +++ b/core/fxge/cfx_windowsrenderdevice.h @@ -14,6 +14,13 @@ #include "core/fxge/cfx_renderdevice.h" +enum WindowsPrintMode { + kModeEmf = 0, + kModeTextOnly = 1, + kModePostScript2 = 2, + kModePostScript3 = 3, +}; + class IFX_RenderDeviceDriver; #if defined(PDFIUM_PRINT_TEXT_WITH_GDI) @@ -25,7 +32,7 @@ extern bool g_pdfium_print_text_with_gdi; extern PDFiumEnsureTypefaceCharactersAccessible g_pdfium_typeface_accessible_func; #endif -extern int g_pdfium_print_postscript_level; +extern int g_pdfium_print_mode; class CFX_WindowsRenderDevice : public CFX_RenderDevice { public: diff --git a/core/fxge/win32/fx_win32_device.cpp b/core/fxge/win32/fx_win32_device.cpp index ef3a7f2f8e..4427755cf5 100644 --- a/core/fxge/win32/fx_win32_device.cpp +++ b/core/fxge/win32/fx_win32_device.cpp @@ -689,7 +689,7 @@ bool CFX_Win32FontInfo::GetFontCharset(void* hFont, int* charset) { } // namespace -int g_pdfium_print_postscript_level = 0; +int g_pdfium_print_mode = WindowsPrintMode::kModeEmf; std::unique_ptr IFX_SystemFontInfo::CreateDefault( const char** pUnused) { @@ -1370,14 +1370,20 @@ IFX_RenderDeviceDriver* CFX_WindowsRenderDevice::CreateDriver(HDC hDC) { int device_type = ::GetDeviceCaps(hDC, TECHNOLOGY); int obj_type = ::GetObjectType(hDC); bool use_printer = device_type == DT_RASPRINTER || - device_type == DT_PLOTTER || obj_type == OBJ_ENHMETADC; + device_type == DT_PLOTTER || + device_type == DT_CHARSTREAM || obj_type == OBJ_ENHMETADC; if (!use_printer) return new CGdiDisplayDriver(hDC); - if (g_pdfium_print_postscript_level == 2 || - g_pdfium_print_postscript_level == 3) { - return new CPSPrinterDriver(hDC, g_pdfium_print_postscript_level, false); - } - return new CGdiPrinterDriver(hDC); + if (g_pdfium_print_mode == WindowsPrintMode::kModeEmf) + return new CGdiPrinterDriver(hDC); + + if (g_pdfium_print_mode == WindowsPrintMode::kModeTextOnly) + return new CTextOnlyPrinterDriver(hDC); + + // Should be PostScript + ASSERT(g_pdfium_print_mode == WindowsPrintMode::kModePostScript2 || + g_pdfium_print_mode == WindowsPrintMode::kModePostScript3); + return new CPSPrinterDriver(hDC, g_pdfium_print_mode, false); } diff --git a/core/fxge/win32/fx_win32_print.cpp b/core/fxge/win32/fx_win32_print.cpp index d7444f43a1..cae3859406 100644 --- a/core/fxge/win32/fx_win32_print.cpp +++ b/core/fxge/win32/fx_win32_print.cpp @@ -492,3 +492,159 @@ bool CPSPrinterDriver::DrawDeviceText(int nChars, return m_PSRenderer.DrawText(nChars, pCharPos, pFont, pObject2Device, font_size, color); } + +CTextOnlyPrinterDriver::CTextOnlyPrinterDriver(HDC hDC) + : m_hDC(hDC), + m_Width(INT_MAX), + m_Height(INT_MAX), + m_HorzSize(INT_MAX), + m_VertSize(INT_MAX), + m_OriginY(0.0f), + m_SetOrigin(false) { + m_nBitsPerPixel = ::GetDeviceCaps(m_hDC, BITSPIXEL); +} + +CTextOnlyPrinterDriver::~CTextOnlyPrinterDriver() { + EndRendering(); +} + +int CTextOnlyPrinterDriver::GetDeviceCaps(int caps_id) const { + switch (caps_id) { + case FXDC_DEVICE_CLASS: + return FXDC_PRINTER; + case FXDC_PIXEL_WIDTH: + return m_Width; + case FXDC_PIXEL_HEIGHT: + return m_Height; + case FXDC_BITS_PIXEL: + return m_nBitsPerPixel; + case FXDC_RENDER_CAPS: + return 0; + case FXDC_HORZ_SIZE: + return m_HorzSize; + case FXDC_VERT_SIZE: + return m_VertSize; + } + return 0; +} + +bool CTextOnlyPrinterDriver::SetClip_PathFill(const CFX_PathData* pPathData, + const CFX_Matrix* pObject2Device, + int fill_mode) { + return true; +} + +bool CTextOnlyPrinterDriver::SetClip_PathStroke( + const CFX_PathData* pPathData, + const CFX_Matrix* pObject2Device, + const CFX_GraphStateData* pGraphState) { + return false; +} + +bool CTextOnlyPrinterDriver::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) { + return false; +} + +bool CTextOnlyPrinterDriver::SetDIBits( + const CFX_RetainPtr& pBitmap, + uint32_t color, + const FX_RECT* pSrcRect, + int left, + int top, + int blend_type) { + return false; +} + +bool CTextOnlyPrinterDriver::GetClipBox(FX_RECT* pRect) { + pRect->left = 0; + pRect->right = m_Width; + pRect->top = 0; + pRect->bottom = m_Height; + return true; +} + +bool CTextOnlyPrinterDriver::StretchDIBits( + const CFX_RetainPtr& 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) { + return false; +} + +bool CTextOnlyPrinterDriver::StartDIBits( + const CFX_RetainPtr& pBitmap, + int bitmap_alpha, + uint32_t color, + const CFX_Matrix* pMatrix, + uint32_t render_flags, + std::unique_ptr* handle, + int blend_type) { + return false; +} + +bool CTextOnlyPrinterDriver::DrawDeviceText(int nChars, + const FXTEXT_CHARPOS* pCharPos, + CFX_Font* pFont, + const CFX_Matrix* pObject2Device, + float font_size, + uint32_t color) { + if (g_pdfium_print_mode != 1) + return false; + if (nChars < 1 || !pFont || !pFont->IsEmbedded() || !pFont->IsTTFont()) + return false; + + // Scale factor used to minimize the kerning problems caused by rounding + // errors below. Value chosen based on the title of https://crbug.com/18383 + const double kScaleFactor = 10; + + CFX_WideString wsText; + int totalLength = nChars; + + // Detect new lines and add a space. Was likely removed by SkPDF if this is + // just text, and spaces seem to be ignored by label printers that use this + // driver. + if (m_SetOrigin && + FXSYS_round(m_OriginY) != FXSYS_round(pObject2Device->f * kScaleFactor)) { + wsText += L" "; + totalLength++; + } + m_OriginY = pObject2Device->f * kScaleFactor; + m_SetOrigin = true; + + // Text + for (int i = 0; i < nChars; ++i) { + // Only works with PDFs from Skia's PDF generator. Cannot handle arbitrary + // values from PDFs. + const FXTEXT_CHARPOS& charpos = pCharPos[i]; + ASSERT(charpos.m_AdjustMatrix[0] == 0); + ASSERT(charpos.m_AdjustMatrix[1] == 0); + ASSERT(charpos.m_AdjustMatrix[2] == 0); + ASSERT(charpos.m_AdjustMatrix[3] == 0); + ASSERT(charpos.m_Origin.y == 0); + + wsText += charpos.m_Unicode; + } + size_t len = totalLength; + CFX_ByteString text = CFX_ByteString::FromUnicode(wsText); + while (len > 0) { + char buffer[1026]; + size_t send_len = std::min(len, static_cast(1024)); + *(reinterpret_cast(buffer)) = send_len; + memcpy(buffer + 2, text.c_str(), send_len); + ::GdiComment(m_hDC, send_len + 2, reinterpret_cast(buffer)); + len -= send_len; + text.Right(len); + } + return true; +} diff --git a/core/fxge/win32/win32_int.h b/core/fxge/win32/win32_int.h index d92d3b333c..c51bae7f67 100644 --- a/core/fxge/win32/win32_int.h +++ b/core/fxge/win32/win32_int.h @@ -333,4 +333,66 @@ class CPSPrinterDriver : public IFX_RenderDeviceDriver { CFX_PSRenderer m_PSRenderer; }; +class CTextOnlyPrinterDriver : public IFX_RenderDeviceDriver { + public: + explicit CTextOnlyPrinterDriver(HDC hDC); + ~CTextOnlyPrinterDriver() override; + + protected: + // IFX_RenderDeviceDriver + int GetDeviceCaps(int caps_id) const override; + void SaveState() override{}; + void RestoreState(bool bKeepSaved) override{}; + bool SetClip_PathFill(const CFX_PathData* pPathData, + const CFX_Matrix* pObject2Device, + int fill_mode) override; + bool SetClip_PathStroke(const CFX_PathData* pPathData, + const CFX_Matrix* pObject2Device, + const CFX_GraphStateData* pGraphState) override; + bool 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) override; + bool GetClipBox(FX_RECT* pRect) override; + bool SetDIBits(const CFX_RetainPtr& pBitmap, + uint32_t color, + const FX_RECT* pSrcRect, + int left, + int top, + int blend_type) override; + bool StretchDIBits(const CFX_RetainPtr& 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) override; + bool StartDIBits(const CFX_RetainPtr& pBitmap, + int bitmap_alpha, + uint32_t color, + const CFX_Matrix* pMatrix, + uint32_t render_flags, + std::unique_ptr* handle, + int blend_type) override; + bool DrawDeviceText(int nChars, + const FXTEXT_CHARPOS* pCharPos, + CFX_Font* pFont, + const CFX_Matrix* pObject2Device, + float font_size, + uint32_t color) override; + + HDC m_hDC; + int m_Width; + int m_Height; + int m_nBitsPerPixel; + int m_HorzSize; + int m_VertSize; + float m_OriginY; + bool m_SetOrigin; +}; #endif // CORE_FXGE_WIN32_WIN32_INT_H_ diff --git a/fpdfsdk/fpdfview.cpp b/fpdfsdk/fpdfview.cpp index 1c282a744d..4d0845b616 100644 --- a/fpdfsdk/fpdfview.cpp +++ b/fpdfsdk/fpdfview.cpp @@ -37,6 +37,7 @@ #include "fpdfsdk/fsdk_define.h" #include "fpdfsdk/fsdk_pauseadapter.h" #include "fpdfsdk/javascript/ijs_runtime.h" +#include "public/fpdf_edit.h" #include "public/fpdf_ext.h" #include "public/fpdf_progressive.h" #include "third_party/base/allocator/partition_allocator/partition_alloc.h" @@ -53,6 +54,16 @@ #if _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_ #include "core/fxge/cfx_windowsrenderdevice.h" + +// These checks are here because core/ and public/ cannot depend on each other. +static_assert(WindowsPrintMode::kModeEmf == FPDF_PRINTMODE_EMF, + "WindowsPrintMode::kModeEmf value mismatch"); +static_assert(WindowsPrintMode::kModeTextOnly == FPDF_PRINTMODE_TEXTONLY, + "WindowsPrintMode::kModeTextOnly value mismatch"); +static_assert(WindowsPrintMode::kModePostScript2 == FPDF_PRINTMODE_POSTSCRIPT2, + "WindowsPrintMode::kModePostScript2 value mismatch"); +static_assert(WindowsPrintMode::kModePostScript3 == FPDF_PRINTMODE_POSTSCRIPT3, + "WindowsPrintMode::kModePostScript3 value mismatch"); #endif namespace { @@ -449,10 +460,10 @@ DLLEXPORT void STDCALL FPDF_SetPrintTextWithGDI(FPDF_BOOL use_gdi) { } #endif // PDFIUM_PRINT_TEXT_WITH_GDI -DLLEXPORT FPDF_BOOL STDCALL FPDF_SetPrintPostscriptLevel(int postscript_level) { - if (postscript_level != 0 && postscript_level != 2 && postscript_level != 3) +DLLEXPORT FPDF_BOOL STDCALL FPDF_SetPrintMode(int mode) { + if (mode < FPDF_PRINTMODE_EMF || mode > FPDF_PRINTMODE_POSTSCRIPT3) return FALSE; - g_pdfium_print_postscript_level = postscript_level; + g_pdfium_print_mode = mode; return TRUE; } #endif // defined(_WIN32) diff --git a/public/fpdf_edit.h b/public/fpdf_edit.h index 4d5826ddbc..aa221fec34 100644 --- a/public/fpdf_edit.h +++ b/public/fpdf_edit.h @@ -42,6 +42,11 @@ #define FPDF_LINEJOIN_ROUND 1 #define FPDF_LINEJOIN_BEVEL 2 +#define FPDF_PRINTMODE_EMF 0 +#define FPDF_PRINTMODE_TEXTONLY 1 +#define FPDF_PRINTMODE_POSTSCRIPT2 2 +#define FPDF_PRINTMODE_POSTSCRIPT3 3 + #ifdef __cplusplus extern "C" { #endif // __cplusplus diff --git a/public/fpdfview.h b/public/fpdfview.h index 1ff0aeb267..df46e9700b 100644 --- a/public/fpdfview.h +++ b/public/fpdfview.h @@ -245,17 +245,18 @@ FPDF_SetTypefaceAccessibleFunc(PDFiumEnsureTypefaceCharactersAccessible func); DLLEXPORT void STDCALL FPDF_SetPrintTextWithGDI(FPDF_BOOL use_gdi); #endif // PDFIUM_PRINT_TEXT_WITH_GDI -// Function: FPDF_SetPrintPostscriptLevel -// Set postscript printing level when printing on Windows. +// Function: FPDF_SetPrintMode +// Set printing mode when printing on Windows. // Experimental API. // Parameters: -// postscript_level - 0 to disable postscript printing, -// 2 to print with postscript level 2, -// 3 to print with postscript level 3. -// All other values are invalid. +// mode - FPDF_PRINTMODE_EMF to output EMF (default) +// FPDF_PRINTMODE_TEXTONLY to output text only (for charstream +// devices) +// FPDF_PRINTMODE_POSTSCRIPT2 to output level 2 postscript +// FPDF_PRINTMODE_POSTSCRIPT3 to output level 3 postscript // Return value: -// True if successful, false if unsucessful (typically invalid input). -DLLEXPORT FPDF_BOOL STDCALL FPDF_SetPrintPostscriptLevel(int postscript_level); +// True if successful, false if unsuccessful (typically invalid input). +DLLEXPORT FPDF_BOOL STDCALL FPDF_SetPrintMode(int mode); #endif // defined(_WIN32) // Function: FPDF_LoadDocument diff --git a/samples/pdfium_test.cc b/samples/pdfium_test.cc index 5eccf22554..85cc0d3526 100644 --- a/samples/pdfium_test.cc +++ b/samples/pdfium_test.cc @@ -1137,9 +1137,9 @@ void RenderPdf(const std::string& name, #if _WIN32 if (options.output_format == OUTPUT_PS2) - FPDF_SetPrintPostscriptLevel(2); + FPDF_SetPrintMode(2); else if (options.output_format == OUTPUT_PS3) - FPDF_SetPrintPostscriptLevel(3); + FPDF_SetPrintMode(3); #endif int page_count = FPDF_GetPageCount(doc.get()); -- cgit v1.2.3