OLD | NEW |
1 // Copyright 2014 PDFium Authors. All rights reserved. | 1 // Copyright 2014 PDFium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com | 5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com |
6 | 6 |
7 #include "core/fxge/include/fx_ge.h" | 7 #include "core/fxge/include/fx_ge.h" |
8 | 8 |
9 #if _FX_OS_ == _FX_WIN32_DESKTOP_ || _FX_OS_ == _FX_WIN64_DESKTOP_ | 9 #if _FX_OS_ == _FX_WIN32_DESKTOP_ || _FX_OS_ == _FX_WIN64_DESKTOP_ |
10 | 10 |
11 #include <windows.h> | 11 #include <windows.h> |
12 | 12 |
| 13 #include <algorithm> |
| 14 |
13 #include "core/fxge/dib/dib_int.h" | 15 #include "core/fxge/dib/dib_int.h" |
14 #include "core/fxge/ge/fx_text_int.h" | 16 #include "core/fxge/ge/fx_text_int.h" |
15 #include "core/fxge/include/fx_freetype.h" | 17 #include "core/fxge/include/fx_freetype.h" |
16 #include "core/fxge/include/fx_ge_win32.h" | 18 #include "core/fxge/include/fx_ge_win32.h" |
17 #include "core/fxge/win32/win32_int.h" | 19 #include "core/fxge/win32/win32_int.h" |
18 | 20 |
| 21 #if defined(PDFIUM_PRINT_TEXT_WITH_GDI) |
| 22 namespace { |
| 23 |
| 24 class ScopedState { |
| 25 public: |
| 26 ScopedState(HDC hDC, HFONT hFont) : m_hDC(hDC) { |
| 27 m_iState = SaveDC(m_hDC); |
| 28 m_hFont = SelectObject(m_hDC, hFont); |
| 29 } |
| 30 |
| 31 ~ScopedState() { |
| 32 HGDIOBJ hFont = SelectObject(m_hDC, m_hFont); |
| 33 DeleteObject(hFont); |
| 34 RestoreDC(m_hDC, m_iState); |
| 35 } |
| 36 |
| 37 private: |
| 38 HDC m_hDC; |
| 39 HGDIOBJ m_hFont; |
| 40 int m_iState; |
| 41 |
| 42 ScopedState(const ScopedState&) = delete; |
| 43 void operator=(const ScopedState&) = delete; |
| 44 }; |
| 45 |
| 46 } // namespace |
| 47 |
| 48 bool g_pdfium_print_text_with_gdi = false; |
| 49 |
| 50 PDFiumEnsureTypefaceCharactersAccessible g_pdfium_typeface_accessible_func = |
| 51 nullptr; |
| 52 #endif |
| 53 |
19 CGdiPrinterDriver::CGdiPrinterDriver(HDC hDC) | 54 CGdiPrinterDriver::CGdiPrinterDriver(HDC hDC) |
20 : CGdiDeviceDriver(hDC, FXDC_PRINTER), | 55 : CGdiDeviceDriver(hDC, FXDC_PRINTER), |
21 m_HorzSize(::GetDeviceCaps(m_hDC, HORZSIZE)), | 56 m_HorzSize(::GetDeviceCaps(m_hDC, HORZSIZE)), |
22 m_VertSize(::GetDeviceCaps(m_hDC, VERTSIZE)) {} | 57 m_VertSize(::GetDeviceCaps(m_hDC, VERTSIZE)) {} |
23 | 58 |
24 CGdiPrinterDriver::~CGdiPrinterDriver() {} | 59 CGdiPrinterDriver::~CGdiPrinterDriver() {} |
25 | 60 |
26 int CGdiPrinterDriver::GetDeviceCaps(int caps_id) const { | 61 int CGdiPrinterDriver::GetDeviceCaps(int caps_id) const { |
27 if (caps_id == FXDC_HORZ_SIZE) | 62 if (caps_id == FXDC_HORZ_SIZE) |
28 return m_HorzSize; | 63 return m_HorzSize; |
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
139 FXSYS_fabs(pMatrix->c) < 0.5f && pMatrix->d != 0) { | 174 FXSYS_fabs(pMatrix->c) < 0.5f && pMatrix->d != 0) { |
140 FX_BOOL bFlipX = pMatrix->a < 0; | 175 FX_BOOL bFlipX = pMatrix->a < 0; |
141 FX_BOOL bFlipY = pMatrix->d > 0; | 176 FX_BOOL bFlipY = pMatrix->d > 0; |
142 return StretchDIBits(pSource, color, | 177 return StretchDIBits(pSource, color, |
143 bFlipX ? full_rect.right : full_rect.left, | 178 bFlipX ? full_rect.right : full_rect.left, |
144 bFlipY ? full_rect.bottom : full_rect.top, | 179 bFlipY ? full_rect.bottom : full_rect.top, |
145 bFlipX ? -full_rect.Width() : full_rect.Width(), | 180 bFlipX ? -full_rect.Width() : full_rect.Width(), |
146 bFlipY ? -full_rect.Height() : full_rect.Height(), | 181 bFlipY ? -full_rect.Height() : full_rect.Height(), |
147 nullptr, 0, blend_type); | 182 nullptr, 0, blend_type); |
148 } | 183 } |
149 if (FXSYS_fabs(pMatrix->a) < 0.5f && FXSYS_fabs(pMatrix->d) < 0.5f) { | 184 if (FXSYS_fabs(pMatrix->a) >= 0.5f || FXSYS_fabs(pMatrix->d) >= 0.5f) |
150 std::unique_ptr<CFX_DIBitmap> pTransformed( | 185 return FALSE; |
151 pSource->SwapXY(pMatrix->c > 0, pMatrix->b < 0)); | 186 |
152 if (!pTransformed) | 187 std::unique_ptr<CFX_DIBitmap> pTransformed( |
| 188 pSource->SwapXY(pMatrix->c > 0, pMatrix->b < 0)); |
| 189 if (!pTransformed) |
| 190 return FALSE; |
| 191 |
| 192 return StretchDIBits(pTransformed.get(), color, full_rect.left, full_rect.top, |
| 193 full_rect.Width(), full_rect.Height(), nullptr, 0, |
| 194 blend_type); |
| 195 } |
| 196 |
| 197 FX_BOOL CGdiPrinterDriver::DrawDeviceText(int nChars, |
| 198 const FXTEXT_CHARPOS* pCharPos, |
| 199 CFX_Font* pFont, |
| 200 CFX_FontCache* pCache, |
| 201 const CFX_Matrix* pObject2Device, |
| 202 FX_FLOAT font_size, |
| 203 uint32_t color) { |
| 204 #if defined(PDFIUM_PRINT_TEXT_WITH_GDI) |
| 205 if (!g_pdfium_print_text_with_gdi) |
| 206 return FALSE; |
| 207 |
| 208 if (nChars < 1 || !pFont || !pFont->IsEmbedded() || !pFont->IsTTFont()) |
| 209 return FALSE; |
| 210 |
| 211 // Font |
| 212 // |
| 213 // Note that |pFont| has the actual font to render with embedded within, but |
| 214 // but unfortunately AddFontMemResourceEx() does not seem to cooperate. |
| 215 // Loading font data to memory seems to work, but then enumerating the fonts |
| 216 // fails to find it. This requires more investigation. In the meanwhile, |
| 217 // assume the printing is happening on the machine that generated the PDF, so |
| 218 // the embedded font, if not a web font, is available through GDI anyway. |
| 219 // TODO(thestig): Figure out why AddFontMemResourceEx() does not work. |
| 220 // Generalize this method to work for all PDFs with embedded fonts. |
| 221 // In sandboxed environments, font loading may not work at all, so this may be |
| 222 // the best possible effort. |
| 223 LOGFONT lf = {}; |
| 224 lf.lfHeight = -font_size; |
| 225 lf.lfWeight = pFont->IsBold() ? FW_BOLD : FW_NORMAL; |
| 226 lf.lfItalic = pFont->IsItalic(); |
| 227 lf.lfCharSet = DEFAULT_CHARSET; |
| 228 |
| 229 const CFX_WideString wsName = pFont->GetFaceName().UTF8Decode(); |
| 230 int iNameLen = std::min(wsName.GetLength(), LF_FACESIZE - 1); |
| 231 memcpy(lf.lfFaceName, wsName.c_str(), sizeof(lf.lfFaceName[0]) * iNameLen); |
| 232 lf.lfFaceName[iNameLen] = 0; |
| 233 |
| 234 HFONT hFont = CreateFontIndirect(&lf); |
| 235 if (!hFont) |
| 236 return FALSE; |
| 237 |
| 238 ScopedState state(m_hDC, hFont); |
| 239 size_t nTextMetricSize = GetOutlineTextMetrics(m_hDC, 0, nullptr); |
| 240 if (nTextMetricSize == 0) { |
| 241 // Give up and fail if there is no way to get the font to try again. |
| 242 if (!g_pdfium_typeface_accessible_func) |
153 return FALSE; | 243 return FALSE; |
154 | 244 |
155 return StretchDIBits(pTransformed.get(), color, full_rect.left, | 245 // Try to get the font. Any letter will do. |
156 full_rect.top, full_rect.Width(), full_rect.Height(), | 246 g_pdfium_typeface_accessible_func(&lf, L"A", 1); |
157 nullptr, 0, blend_type); | 247 nTextMetricSize = GetOutlineTextMetrics(m_hDC, 0, nullptr); |
| 248 if (nTextMetricSize == 0) |
| 249 return FALSE; |
158 } | 250 } |
| 251 |
| 252 std::vector<BYTE> buf(nTextMetricSize); |
| 253 OUTLINETEXTMETRIC* pTextMetric = |
| 254 reinterpret_cast<OUTLINETEXTMETRIC*>(buf.data()); |
| 255 if (GetOutlineTextMetrics(m_hDC, nTextMetricSize, pTextMetric) == 0) |
| 256 return FALSE; |
| 257 |
| 258 // If the selected font is not the requested font, then bail out. This can |
| 259 // happen with web fonts, for example. |
| 260 wchar_t* wsSelectedName = reinterpret_cast<wchar_t*>( |
| 261 buf.data() + reinterpret_cast<size_t>(pTextMetric->otmpFaceName)); |
| 262 if (wsName != wsSelectedName) |
| 263 return FALSE; |
| 264 |
| 265 // Transforms |
| 266 SetGraphicsMode(m_hDC, GM_ADVANCED); |
| 267 XFORM xform; |
| 268 xform.eM11 = pObject2Device->GetA(); |
| 269 xform.eM12 = pObject2Device->GetB(); |
| 270 xform.eM21 = -pObject2Device->GetC(); |
| 271 xform.eM22 = -pObject2Device->GetD(); |
| 272 xform.eDx = pObject2Device->GetE(); |
| 273 xform.eDy = pObject2Device->GetF(); |
| 274 ModifyWorldTransform(m_hDC, &xform, MWT_LEFTMULTIPLY); |
| 275 |
| 276 // Color |
| 277 int iUnusedAlpha; |
| 278 FX_COLORREF rgb; |
| 279 ArgbDecode(color, iUnusedAlpha, rgb); |
| 280 SetTextColor(m_hDC, rgb); |
| 281 SetBkMode(m_hDC, TRANSPARENT); |
| 282 |
| 283 // Text |
| 284 CFX_WideString wsText; |
| 285 for (int i = 0; i < nChars; ++i) { |
| 286 // Only works with PDFs from Skia's PDF generator. Cannot handle arbitrary |
| 287 // values from PDFs. |
| 288 const FXTEXT_CHARPOS& charpos = pCharPos[i]; |
| 289 ASSERT(charpos.m_OriginX == 0); |
| 290 ASSERT(charpos.m_OriginY == 0); |
| 291 ASSERT(charpos.m_AdjustMatrix[0] == 0); |
| 292 ASSERT(charpos.m_AdjustMatrix[1] == 0); |
| 293 ASSERT(charpos.m_AdjustMatrix[2] == 0); |
| 294 ASSERT(charpos.m_AdjustMatrix[3] == 0); |
| 295 wsText += charpos.m_GlyphIndex; |
| 296 } |
| 297 |
| 298 // Draw |
| 299 SetTextAlign(m_hDC, TA_LEFT | TA_BASELINE); |
| 300 if (ExtTextOutW(m_hDC, 0, 0, ETO_GLYPH_INDEX, nullptr, wsText.c_str(), nChars, |
| 301 nullptr)) { |
| 302 return TRUE; |
| 303 } |
| 304 |
| 305 // Give up and fail if there is no way to get the font to try again. |
| 306 if (!g_pdfium_typeface_accessible_func) |
| 307 return FALSE; |
| 308 |
| 309 // Try to get the font and draw again. |
| 310 g_pdfium_typeface_accessible_func(&lf, wsText.c_str(), nChars); |
| 311 return ExtTextOutW(m_hDC, 0, 0, ETO_GLYPH_INDEX, nullptr, wsText.c_str(), |
| 312 nChars, nullptr); |
| 313 #else |
159 return FALSE; | 314 return FALSE; |
| 315 #endif |
160 } | 316 } |
161 | 317 |
162 #endif | 318 #endif // _FX_OS_ == _FX_WIN32_DESKTOP_ || _FX_OS_ == _FX_WIN64_DESKTOP_ |
OLD | NEW |