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/fxcrt/include/fx_system.h" | 7 #include "core/fxcrt/include/fx_system.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 |
(...skipping 191 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
202 const CFX_Matrix* pObject2Device, | 202 const CFX_Matrix* pObject2Device, |
203 FX_FLOAT font_size, | 203 FX_FLOAT font_size, |
204 uint32_t color) { | 204 uint32_t color) { |
205 #if defined(PDFIUM_PRINT_TEXT_WITH_GDI) | 205 #if defined(PDFIUM_PRINT_TEXT_WITH_GDI) |
206 if (!g_pdfium_print_text_with_gdi) | 206 if (!g_pdfium_print_text_with_gdi) |
207 return FALSE; | 207 return FALSE; |
208 | 208 |
209 if (nChars < 1 || !pFont || !pFont->IsEmbedded() || !pFont->IsTTFont()) | 209 if (nChars < 1 || !pFont || !pFont->IsEmbedded() || !pFont->IsTTFont()) |
210 return FALSE; | 210 return FALSE; |
211 | 211 |
| 212 // Scale factor used to minimize the kerning problems caused by rounding |
| 213 // errors below. Value choosen based on the title of https://crbug.com/18383 |
| 214 const double kScaleFactor = 10; |
| 215 |
212 // Font | 216 // Font |
213 // | 217 // |
214 // Note that |pFont| has the actual font to render with embedded within, but | 218 // Note that |pFont| has the actual font to render with embedded within, but |
215 // but unfortunately AddFontMemResourceEx() does not seem to cooperate. | 219 // but unfortunately AddFontMemResourceEx() does not seem to cooperate. |
216 // Loading font data to memory seems to work, but then enumerating the fonts | 220 // Loading font data to memory seems to work, but then enumerating the fonts |
217 // fails to find it. This requires more investigation. In the meanwhile, | 221 // fails to find it. This requires more investigation. In the meanwhile, |
218 // assume the printing is happening on the machine that generated the PDF, so | 222 // assume the printing is happening on the machine that generated the PDF, so |
219 // the embedded font, if not a web font, is available through GDI anyway. | 223 // the embedded font, if not a web font, is available through GDI anyway. |
220 // TODO(thestig): Figure out why AddFontMemResourceEx() does not work. | 224 // TODO(thestig): Figure out why AddFontMemResourceEx() does not work. |
221 // Generalize this method to work for all PDFs with embedded fonts. | 225 // Generalize this method to work for all PDFs with embedded fonts. |
222 // In sandboxed environments, font loading may not work at all, so this may be | 226 // In sandboxed environments, font loading may not work at all, so this may be |
223 // the best possible effort. | 227 // the best possible effort. |
224 LOGFONT lf = {}; | 228 LOGFONT lf = {}; |
225 lf.lfHeight = -font_size; | 229 lf.lfHeight = -font_size * kScaleFactor; |
226 lf.lfWeight = pFont->IsBold() ? FW_BOLD : FW_NORMAL; | 230 lf.lfWeight = pFont->IsBold() ? FW_BOLD : FW_NORMAL; |
227 lf.lfItalic = pFont->IsItalic(); | 231 lf.lfItalic = pFont->IsItalic(); |
228 lf.lfCharSet = DEFAULT_CHARSET; | 232 lf.lfCharSet = DEFAULT_CHARSET; |
229 | 233 |
230 const CFX_WideString wsName = pFont->GetFaceName().UTF8Decode(); | 234 const CFX_WideString wsName = pFont->GetFaceName().UTF8Decode(); |
231 int iNameLen = std::min(wsName.GetLength(), LF_FACESIZE - 1); | 235 int iNameLen = std::min(wsName.GetLength(), LF_FACESIZE - 1); |
232 memcpy(lf.lfFaceName, wsName.c_str(), sizeof(lf.lfFaceName[0]) * iNameLen); | 236 memcpy(lf.lfFaceName, wsName.c_str(), sizeof(lf.lfFaceName[0]) * iNameLen); |
233 lf.lfFaceName[iNameLen] = 0; | 237 lf.lfFaceName[iNameLen] = 0; |
234 | 238 |
235 HFONT hFont = CreateFontIndirect(&lf); | 239 HFONT hFont = CreateFontIndirect(&lf); |
(...skipping 23 matching lines...) Expand all Loading... |
259 // If the selected font is not the requested font, then bail out. This can | 263 // If the selected font is not the requested font, then bail out. This can |
260 // happen with web fonts, for example. | 264 // happen with web fonts, for example. |
261 wchar_t* wsSelectedName = reinterpret_cast<wchar_t*>( | 265 wchar_t* wsSelectedName = reinterpret_cast<wchar_t*>( |
262 buf.data() + reinterpret_cast<size_t>(pTextMetric->otmpFaceName)); | 266 buf.data() + reinterpret_cast<size_t>(pTextMetric->otmpFaceName)); |
263 if (wsName != wsSelectedName) | 267 if (wsName != wsSelectedName) |
264 return FALSE; | 268 return FALSE; |
265 | 269 |
266 // Transforms | 270 // Transforms |
267 SetGraphicsMode(m_hDC, GM_ADVANCED); | 271 SetGraphicsMode(m_hDC, GM_ADVANCED); |
268 XFORM xform; | 272 XFORM xform; |
269 xform.eM11 = pObject2Device->GetA(); | 273 xform.eM11 = pObject2Device->GetA() / kScaleFactor; |
270 xform.eM12 = pObject2Device->GetB(); | 274 xform.eM12 = pObject2Device->GetB() / kScaleFactor; |
271 xform.eM21 = -pObject2Device->GetC(); | 275 xform.eM21 = -pObject2Device->GetC() / kScaleFactor; |
272 xform.eM22 = -pObject2Device->GetD(); | 276 xform.eM22 = -pObject2Device->GetD() / kScaleFactor; |
273 xform.eDx = pObject2Device->GetE(); | 277 xform.eDx = pObject2Device->GetE(); |
274 xform.eDy = pObject2Device->GetF(); | 278 xform.eDy = pObject2Device->GetF(); |
275 ModifyWorldTransform(m_hDC, &xform, MWT_LEFTMULTIPLY); | 279 ModifyWorldTransform(m_hDC, &xform, MWT_LEFTMULTIPLY); |
276 | 280 |
277 // Color | 281 // Color |
278 int iUnusedAlpha; | 282 int iUnusedAlpha; |
279 FX_COLORREF rgb; | 283 FX_COLORREF rgb; |
280 ArgbDecode(color, iUnusedAlpha, rgb); | 284 ArgbDecode(color, iUnusedAlpha, rgb); |
281 SetTextColor(m_hDC, rgb); | 285 SetTextColor(m_hDC, rgb); |
282 SetBkMode(m_hDC, TRANSPARENT); | 286 SetBkMode(m_hDC, TRANSPARENT); |
283 | 287 |
284 // Text | 288 // Text |
285 CFX_WideString wsText; | 289 CFX_WideString wsText; |
| 290 std::vector<INT> spacing(nChars); |
| 291 FX_FLOAT fPreviousOriginX = 0; |
286 for (int i = 0; i < nChars; ++i) { | 292 for (int i = 0; i < nChars; ++i) { |
287 // Only works with PDFs from Skia's PDF generator. Cannot handle arbitrary | 293 // Only works with PDFs from Skia's PDF generator. Cannot handle arbitrary |
288 // values from PDFs. | 294 // values from PDFs. |
289 const FXTEXT_CHARPOS& charpos = pCharPos[i]; | 295 const FXTEXT_CHARPOS& charpos = pCharPos[i]; |
290 ASSERT(charpos.m_OriginX == 0); | |
291 ASSERT(charpos.m_OriginY == 0); | |
292 ASSERT(charpos.m_AdjustMatrix[0] == 0); | 296 ASSERT(charpos.m_AdjustMatrix[0] == 0); |
293 ASSERT(charpos.m_AdjustMatrix[1] == 0); | 297 ASSERT(charpos.m_AdjustMatrix[1] == 0); |
294 ASSERT(charpos.m_AdjustMatrix[2] == 0); | 298 ASSERT(charpos.m_AdjustMatrix[2] == 0); |
295 ASSERT(charpos.m_AdjustMatrix[3] == 0); | 299 ASSERT(charpos.m_AdjustMatrix[3] == 0); |
| 300 ASSERT(charpos.m_OriginY == 0); |
| 301 |
| 302 // Round the spacing to the nearest integer, but keep track of the rounding |
| 303 // error for calculating the next spacing value. |
| 304 FX_FLOAT fOriginX = charpos.m_OriginX * kScaleFactor; |
| 305 FX_FLOAT fPixelSpacing = fOriginX - fPreviousOriginX; |
| 306 spacing[i] = FXSYS_round(fPixelSpacing); |
| 307 fPreviousOriginX = fOriginX - (fPixelSpacing - spacing[i]); |
| 308 |
296 wsText += charpos.m_GlyphIndex; | 309 wsText += charpos.m_GlyphIndex; |
297 } | 310 } |
298 | 311 |
299 // Draw | 312 // Draw |
300 SetTextAlign(m_hDC, TA_LEFT | TA_BASELINE); | 313 SetTextAlign(m_hDC, TA_LEFT | TA_BASELINE); |
301 if (ExtTextOutW(m_hDC, 0, 0, ETO_GLYPH_INDEX, nullptr, wsText.c_str(), nChars, | 314 if (ExtTextOutW(m_hDC, 0, 0, ETO_GLYPH_INDEX, nullptr, wsText.c_str(), nChars, |
302 nullptr)) { | 315 nChars > 1 ? &spacing[1] : nullptr)) { |
303 return TRUE; | 316 return TRUE; |
304 } | 317 } |
305 | 318 |
306 // Give up and fail if there is no way to get the font to try again. | 319 // Give up and fail if there is no way to get the font to try again. |
307 if (!g_pdfium_typeface_accessible_func) | 320 if (!g_pdfium_typeface_accessible_func) |
308 return FALSE; | 321 return FALSE; |
309 | 322 |
310 // Try to get the font and draw again. | 323 // Try to get the font and draw again. |
311 g_pdfium_typeface_accessible_func(&lf, wsText.c_str(), nChars); | 324 g_pdfium_typeface_accessible_func(&lf, wsText.c_str(), nChars); |
312 return ExtTextOutW(m_hDC, 0, 0, ETO_GLYPH_INDEX, nullptr, wsText.c_str(), | 325 return ExtTextOutW(m_hDC, 0, 0, ETO_GLYPH_INDEX, nullptr, wsText.c_str(), |
313 nChars, nullptr); | 326 nChars, nChars > 1 ? &spacing[1] : nullptr); |
314 #else | 327 #else |
315 return FALSE; | 328 return FALSE; |
316 #endif | 329 #endif |
317 } | 330 } |
318 | 331 |
319 #endif // _FX_OS_ == _FX_WIN32_DESKTOP_ || _FX_OS_ == _FX_WIN64_DESKTOP_ | 332 #endif // _FX_OS_ == _FX_WIN32_DESKTOP_ || _FX_OS_ == _FX_WIN64_DESKTOP_ |
OLD | NEW |