| 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_
|
|
|