diff options
author | thestig <thestig@chromium.org> | 2016-07-18 13:45:44 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2016-07-18 13:45:44 -0700 |
commit | fdb35ffb8d4bd283dd8f5905936f5c400fea3394 (patch) | |
tree | 715c7842a6a3b654ec95c11cd05ecf9a8d7900a4 /core/fxge | |
parent | 34965459f4f53a77f6c925292304eface57d12c6 (diff) | |
download | pdfium-fdb35ffb8d4bd283dd8f5905936f5c400fea3394.tar.xz |
Implement CGdiPrinterDriver::DrawDeviceText().chromium/2801
This is sufficient to print text with GDI for PDFs generated by Chromium
and cannot print any arbitrary PDF. Text that cannot be printed will be
drawn as glyphs as before.
BUG=409472
Review-Url: https://codereview.chromium.org/2113563003
Diffstat (limited to 'core/fxge')
-rw-r--r-- | core/fxge/include/fx_ge_win32.h | 10 | ||||
-rw-r--r-- | core/fxge/win32/fx_win32_print.cpp | 172 | ||||
-rw-r--r-- | core/fxge/win32/win32_int.h | 7 |
3 files changed, 181 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; |