Index: core/fxge/win32/fx_win32_print.cpp |
diff --git a/core/fxge/win32/fx_win32_print.cpp b/core/fxge/win32/fx_win32_print.cpp |
index aef6062e73ec12ca290b7605f1e8a88054d6315c..e1071e79f0fd7751b98ca94b8ff0ddb22914ba07 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_ |