summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/fxge/include/fx_ge_win32.h10
-rw-r--r--core/fxge/win32/fx_win32_print.cpp172
-rw-r--r--core/fxge/win32/win32_int.h7
-rw-r--r--fpdfsdk/fpdfview.cpp11
-rw-r--r--public/fpdfview.h28
5 files changed, 220 insertions, 8 deletions
diff --git a/core/fxge/include/fx_ge_win32.h b/core/fxge/include/fx_ge_win32.h
index c0889c1852..5b57863ab5 100644
--- a/core/fxge/include/fx_ge_win32.h
+++ b/core/fxge/include/fx_ge_win32.h
@@ -16,6 +16,16 @@
class IFX_RenderDeviceDriver;
+#if defined(PDFIUM_PRINT_TEXT_WITH_GDI)
+typedef void (*PDFiumEnsureTypefaceCharactersAccessible)(const LOGFONT* font,
+ const wchar_t* text,
+ size_t text_length);
+
+extern bool g_pdfium_print_text_with_gdi;
+extern PDFiumEnsureTypefaceCharactersAccessible
+ g_pdfium_typeface_accessible_func;
+#endif
+
typedef struct WINDIB_Open_Args_ {
int flags;
diff --git a/core/fxge/win32/fx_win32_print.cpp b/core/fxge/win32/fx_win32_print.cpp
index aef6062e73..e1071e79f0 100644
--- a/core/fxge/win32/fx_win32_print.cpp
+++ b/core/fxge/win32/fx_win32_print.cpp
@@ -10,12 +10,47 @@
#include <windows.h>
+#include <algorithm>
+
#include "core/fxge/dib/dib_int.h"
#include "core/fxge/ge/fx_text_int.h"
#include "core/fxge/include/fx_freetype.h"
#include "core/fxge/include/fx_ge_win32.h"
#include "core/fxge/win32/win32_int.h"
+#if defined(PDFIUM_PRINT_TEXT_WITH_GDI)
+namespace {
+
+class ScopedState {
+ public:
+ ScopedState(HDC hDC, HFONT hFont) : m_hDC(hDC) {
+ m_iState = SaveDC(m_hDC);
+ m_hFont = SelectObject(m_hDC, hFont);
+ }
+
+ ~ScopedState() {
+ HGDIOBJ hFont = SelectObject(m_hDC, m_hFont);
+ DeleteObject(hFont);
+ RestoreDC(m_hDC, m_iState);
+ }
+
+ private:
+ HDC m_hDC;
+ HGDIOBJ m_hFont;
+ int m_iState;
+
+ ScopedState(const ScopedState&) = delete;
+ void operator=(const ScopedState&) = delete;
+};
+
+} // namespace
+
+bool g_pdfium_print_text_with_gdi = false;
+
+PDFiumEnsureTypefaceCharactersAccessible g_pdfium_typeface_accessible_func =
+ nullptr;
+#endif
+
CGdiPrinterDriver::CGdiPrinterDriver(HDC hDC)
: CGdiDeviceDriver(hDC, FXDC_PRINTER),
m_HorzSize(::GetDeviceCaps(m_hDC, HORZSIZE)),
@@ -146,17 +181,138 @@ FX_BOOL CGdiPrinterDriver::StartDIBits(const CFX_DIBSource* pSource,
bFlipY ? -full_rect.Height() : full_rect.Height(),
nullptr, 0, blend_type);
}
- if (FXSYS_fabs(pMatrix->a) < 0.5f && FXSYS_fabs(pMatrix->d) < 0.5f) {
- std::unique_ptr<CFX_DIBitmap> pTransformed(
- pSource->SwapXY(pMatrix->c > 0, pMatrix->b < 0));
- if (!pTransformed)
+ if (FXSYS_fabs(pMatrix->a) >= 0.5f || FXSYS_fabs(pMatrix->d) >= 0.5f)
+ return FALSE;
+
+ std::unique_ptr<CFX_DIBitmap> pTransformed(
+ pSource->SwapXY(pMatrix->c > 0, pMatrix->b < 0));
+ if (!pTransformed)
+ return FALSE;
+
+ return StretchDIBits(pTransformed.get(), color, full_rect.left, full_rect.top,
+ full_rect.Width(), full_rect.Height(), nullptr, 0,
+ blend_type);
+}
+
+FX_BOOL CGdiPrinterDriver::DrawDeviceText(int nChars,
+ const FXTEXT_CHARPOS* pCharPos,
+ CFX_Font* pFont,
+ CFX_FontCache* pCache,
+ const CFX_Matrix* pObject2Device,
+ FX_FLOAT font_size,
+ uint32_t color) {
+#if defined(PDFIUM_PRINT_TEXT_WITH_GDI)
+ if (!g_pdfium_print_text_with_gdi)
+ return FALSE;
+
+ if (nChars < 1 || !pFont || !pFont->IsEmbedded() || !pFont->IsTTFont())
+ return FALSE;
+
+ // Font
+ //
+ // Note that |pFont| has the actual font to render with embedded within, but
+ // but unfortunately AddFontMemResourceEx() does not seem to cooperate.
+ // Loading font data to memory seems to work, but then enumerating the fonts
+ // fails to find it. This requires more investigation. In the meanwhile,
+ // assume the printing is happening on the machine that generated the PDF, so
+ // the embedded font, if not a web font, is available through GDI anyway.
+ // TODO(thestig): Figure out why AddFontMemResourceEx() does not work.
+ // Generalize this method to work for all PDFs with embedded fonts.
+ // In sandboxed environments, font loading may not work at all, so this may be
+ // the best possible effort.
+ LOGFONT lf = {};
+ lf.lfHeight = -font_size;
+ lf.lfWeight = pFont->IsBold() ? FW_BOLD : FW_NORMAL;
+ lf.lfItalic = pFont->IsItalic();
+ lf.lfCharSet = DEFAULT_CHARSET;
+
+ const CFX_WideString wsName = pFont->GetFaceName().UTF8Decode();
+ int iNameLen = std::min(wsName.GetLength(), LF_FACESIZE - 1);
+ memcpy(lf.lfFaceName, wsName.c_str(), sizeof(lf.lfFaceName[0]) * iNameLen);
+ lf.lfFaceName[iNameLen] = 0;
+
+ HFONT hFont = CreateFontIndirect(&lf);
+ if (!hFont)
+ return FALSE;
+
+ ScopedState state(m_hDC, hFont);
+ size_t nTextMetricSize = GetOutlineTextMetrics(m_hDC, 0, nullptr);
+ if (nTextMetricSize == 0) {
+ // Give up and fail if there is no way to get the font to try again.
+ if (!g_pdfium_typeface_accessible_func)
return FALSE;
- return StretchDIBits(pTransformed.get(), color, full_rect.left,
- full_rect.top, full_rect.Width(), full_rect.Height(),
- nullptr, 0, blend_type);
+ // Try to get the font. Any letter will do.
+ g_pdfium_typeface_accessible_func(&lf, L"A", 1);
+ nTextMetricSize = GetOutlineTextMetrics(m_hDC, 0, nullptr);
+ if (nTextMetricSize == 0)
+ return FALSE;
}
+
+ std::vector<BYTE> buf(nTextMetricSize);
+ OUTLINETEXTMETRIC* pTextMetric =
+ reinterpret_cast<OUTLINETEXTMETRIC*>(buf.data());
+ if (GetOutlineTextMetrics(m_hDC, nTextMetricSize, pTextMetric) == 0)
+ return FALSE;
+
+ // If the selected font is not the requested font, then bail out. This can
+ // happen with web fonts, for example.
+ wchar_t* wsSelectedName = reinterpret_cast<wchar_t*>(
+ buf.data() + reinterpret_cast<size_t>(pTextMetric->otmpFaceName));
+ if (wsName != wsSelectedName)
+ return FALSE;
+
+ // Transforms
+ SetGraphicsMode(m_hDC, GM_ADVANCED);
+ XFORM xform;
+ xform.eM11 = pObject2Device->GetA();
+ xform.eM12 = pObject2Device->GetB();
+ xform.eM21 = -pObject2Device->GetC();
+ xform.eM22 = -pObject2Device->GetD();
+ xform.eDx = pObject2Device->GetE();
+ xform.eDy = pObject2Device->GetF();
+ ModifyWorldTransform(m_hDC, &xform, MWT_LEFTMULTIPLY);
+
+ // Color
+ int iUnusedAlpha;
+ FX_COLORREF rgb;
+ ArgbDecode(color, iUnusedAlpha, rgb);
+ SetTextColor(m_hDC, rgb);
+ SetBkMode(m_hDC, TRANSPARENT);
+
+ // Text
+ CFX_WideString wsText;
+ 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_OriginX == 0);
+ ASSERT(charpos.m_OriginY == 0);
+ ASSERT(charpos.m_AdjustMatrix[0] == 0);
+ ASSERT(charpos.m_AdjustMatrix[1] == 0);
+ ASSERT(charpos.m_AdjustMatrix[2] == 0);
+ ASSERT(charpos.m_AdjustMatrix[3] == 0);
+ wsText += charpos.m_GlyphIndex;
+ }
+
+ // Draw
+ SetTextAlign(m_hDC, TA_LEFT | TA_BASELINE);
+ if (ExtTextOutW(m_hDC, 0, 0, ETO_GLYPH_INDEX, nullptr, wsText.c_str(), nChars,
+ nullptr)) {
+ return TRUE;
+ }
+
+ // Give up and fail if there is no way to get the font to try again.
+ if (!g_pdfium_typeface_accessible_func)
+ return FALSE;
+
+ // Try to get the font and draw again.
+ g_pdfium_typeface_accessible_func(&lf, wsText.c_str(), nChars);
+ return ExtTextOutW(m_hDC, 0, 0, ETO_GLYPH_INDEX, nullptr, wsText.c_str(),
+ nChars, nullptr);
+#else
return FALSE;
+#endif
}
-#endif
+#endif // _FX_OS_ == _FX_WIN32_DESKTOP_ || _FX_OS_ == _FX_WIN64_DESKTOP_
diff --git a/core/fxge/win32/win32_int.h b/core/fxge/win32/win32_int.h
index e844f5cf24..c7a7606155 100644
--- a/core/fxge/win32/win32_int.h
+++ b/core/fxge/win32/win32_int.h
@@ -239,6 +239,13 @@ class CGdiPrinterDriver : public CGdiDeviceDriver {
uint32_t render_flags,
void*& handle,
int blend_type) override;
+ FX_BOOL DrawDeviceText(int nChars,
+ const FXTEXT_CHARPOS* pCharPos,
+ CFX_Font* pFont,
+ CFX_FontCache* pCache,
+ const CFX_Matrix* pObject2Device,
+ FX_FLOAT font_size,
+ uint32_t color) override;
const int m_HorzSize;
const int m_VertSize;
diff --git a/fpdfsdk/fpdfview.cpp b/fpdfsdk/fpdfview.cpp
index 646fb46f72..34e7d23619 100644
--- a/fpdfsdk/fpdfview.cpp
+++ b/fpdfsdk/fpdfview.cpp
@@ -334,6 +334,17 @@ DLLEXPORT void STDCALL FPDF_SetSandBoxPolicy(FPDF_DWORD policy,
return FSDK_SetSandBoxPolicy(policy, enable);
}
+#if defined(_WIN32) && defined(PDFIUM_PRINT_TEXT_WITH_GDI)
+DLLEXPORT void STDCALL
+FPDF_SetTypefaceAccessibleFunc(PDFiumEnsureTypefaceCharactersAccessible func) {
+ g_pdfium_typeface_accessible_func = func;
+}
+
+DLLEXPORT void STDCALL FPDF_SetPrintTextWithGDI(FPDF_BOOL use_gdi) {
+ g_pdfium_print_text_with_gdi = !!use_gdi;
+}
+#endif
+
DLLEXPORT FPDF_DOCUMENT STDCALL FPDF_LoadDocument(FPDF_STRING file_path,
FPDF_BYTESTRING password) {
// NOTE: the creation of the file needs to be by the embedder on the
diff --git a/public/fpdfview.h b/public/fpdfview.h
index cea431a498..cbb577b2fd 100644
--- a/public/fpdfview.h
+++ b/public/fpdfview.h
@@ -211,6 +211,34 @@ DLLEXPORT void STDCALL FPDF_DestroyLibrary();
DLLEXPORT void STDCALL FPDF_SetSandBoxPolicy(FPDF_DWORD policy,
FPDF_BOOL enable);
+#if defined(_WIN32) && defined(PDFIUM_PRINT_TEXT_WITH_GDI)
+// Pointer to a helper function to make |font| with |text| of |text_length|
+// accessible when printing text with GDI. This is useful in sandboxed
+// environments where PDFium's access to GDI may be restricted.
+typedef void (*PDFiumEnsureTypefaceCharactersAccessible)(const LOGFONT* font,
+ const wchar_t* text,
+ size_t text_length);
+
+// Function: FPDF_SetTypefaceAccessibleFunc
+// Set the function pointer that makes GDI fonts available in sandboxed
+// environments. Experimental API.
+// Parameters:
+// func - A function pointer. See description above.
+// Return value:
+// None.
+DLLEXPORT void STDCALL
+FPDF_SetTypefaceAccessibleFunc(PDFiumEnsureTypefaceCharactersAccessible func);
+
+// Function: FPDF_SetPrintTextWithGDI
+// Set whether to use GDI to draw fonts when printing on Windows.
+// Experimental API.
+// Parameters:
+// use_gdi - Set to true to enable printing text with GDI.
+// Return value:
+// None.
+DLLEXPORT void STDCALL FPDF_SetPrintTextWithGDI(FPDF_BOOL use_gdi);
+#endif
+
// Function: FPDF_LoadDocument
// Open and load a PDF document.
// Parameters: