Chromium Code Reviews| 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 |
|
Ilya Kulshin
2016/07/12 23:40:56
This doesn't sound like a safe assumption, especia
Lei Zhang
2016/07/13 00:01:05
This code path is gated on |g_pdfium_print_text_wi
|
| + // 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_ |