diff options
Diffstat (limited to 'core/fxge/win32')
-rw-r--r-- | core/fxge/win32/fx_win32_print.cpp | 172 | ||||
-rw-r--r-- | core/fxge/win32/win32_int.h | 7 |
2 files changed, 171 insertions, 8 deletions
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; |