1 // Copyright 2014 PDFium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6
7 #include <windows.h>
8
9 #include <algorithm>
10 #include <memory>
11 #include <vector>
12
13 #include "core/fxcrt/fx_system.h"
14 #include "core/fxge/cfx_font.h"
15 #include "core/fxge/cfx_windowsrenderdevice.h"
16 #include "core/fxge/dib/cfx_dibextractor.h"
17 #include "core/fxge/dib/cfx_imagerenderer.h"
18 #include "core/fxge/dib/cstretchengine.h"
19 #include "core/fxge/fx_freetype.h"
20 #include "core/fxge/win32/cpsoutput.h"
21 #include "core/fxge/win32/win32_int.h"
22 #include "third_party/base/ptr_util.h"
23
24 #if defined(PDFIUM_PRINT_TEXT_WITH_GDI)
25 namespace {
26
27 class ScopedState {
28 public:
ScopedState(HDC hDC,HFONT hFont)29 ScopedState(HDC hDC, HFONT hFont) : m_hDC(hDC) {
30 m_iState = SaveDC(m_hDC);
31 m_hFont = SelectObject(m_hDC, hFont);
32 }
33
~ScopedState()34 ~ScopedState() {
35 HGDIOBJ hFont = SelectObject(m_hDC, m_hFont);
36 DeleteObject(hFont);
37 RestoreDC(m_hDC, m_iState);
38 }
39
40 private:
41 HDC m_hDC;
42 HGDIOBJ m_hFont;
43 int m_iState;
44
45 ScopedState(const ScopedState&) = delete;
46 void operator=(const ScopedState&) = delete;
47 };
48
49 } // namespace
50
51 bool g_pdfium_print_text_with_gdi = false;
52
53 PDFiumEnsureTypefaceCharactersAccessible g_pdfium_typeface_accessible_func =
54 nullptr;
55 #endif
56
CGdiPrinterDriver(HDC hDC)57 CGdiPrinterDriver::CGdiPrinterDriver(HDC hDC)
58 : CGdiDeviceDriver(hDC, FXDC_PRINTER),
59 m_HorzSize(::GetDeviceCaps(m_hDC, HORZSIZE)),
60 m_VertSize(::GetDeviceCaps(m_hDC, VERTSIZE)) {}
61
~CGdiPrinterDriver()62 CGdiPrinterDriver::~CGdiPrinterDriver() {}
63
GetDeviceCaps(int caps_id) const64 int CGdiPrinterDriver::GetDeviceCaps(int caps_id) const {
65 if (caps_id == FXDC_HORZ_SIZE)
66 return m_HorzSize;
67 if (caps_id == FXDC_VERT_SIZE)
68 return m_VertSize;
69 return CGdiDeviceDriver::GetDeviceCaps(caps_id);
70 }
71
SetDIBits(const RetainPtr<CFX_DIBSource> & pSource,uint32_t color,const FX_RECT * pSrcRect,int left,int top,int blend_type)72 bool CGdiPrinterDriver::SetDIBits(const RetainPtr<CFX_DIBSource>& pSource,
73 uint32_t color,
74 const FX_RECT* pSrcRect,
75 int left,
76 int top,
77 int blend_type) {
78 if (pSource->IsAlphaMask()) {
79 FX_RECT clip_rect(left, top, left + pSrcRect->Width(),
80 top + pSrcRect->Height());
81 return StretchDIBits(pSource, color, left - pSrcRect->left,
82 top - pSrcRect->top, pSource->GetWidth(),
83 pSource->GetHeight(), &clip_rect, 0,
84 FXDIB_BLEND_NORMAL);
85 }
86 ASSERT(pSource && !pSource->IsAlphaMask() && pSrcRect);
87 ASSERT(blend_type == FXDIB_BLEND_NORMAL);
88 if (pSource->HasAlpha())
89 return false;
90
91 CFX_DIBExtractor temp(pSource);
92 RetainPtr<CFX_DIBitmap> pBitmap = temp.GetBitmap();
93 if (!pBitmap)
94 return false;
95
96 return GDI_SetDIBits(pBitmap, pSrcRect, left, top);
97 }
98
StretchDIBits(const RetainPtr<CFX_DIBSource> & pSource,uint32_t color,int dest_left,int dest_top,int dest_width,int dest_height,const FX_RECT * pClipRect,uint32_t flags,int blend_type)99 bool CGdiPrinterDriver::StretchDIBits(const RetainPtr<CFX_DIBSource>& pSource,
100 uint32_t color,
101 int dest_left,
102 int dest_top,
103 int dest_width,
104 int dest_height,
105 const FX_RECT* pClipRect,
106 uint32_t flags,
107 int blend_type) {
108 if (pSource->IsAlphaMask()) {
109 int alpha = FXARGB_A(color);
110 if (pSource->GetBPP() != 1 || alpha != 255)
111 return false;
112
113 if (dest_width < 0 || dest_height < 0) {
114 RetainPtr<CFX_DIBitmap> pFlipped =
115 pSource->FlipImage(dest_width < 0, dest_height < 0);
116 if (!pFlipped)
117 return false;
118
119 if (dest_width < 0)
120 dest_left += dest_width;
121 if (dest_height < 0)
122 dest_top += dest_height;
123
124 return GDI_StretchBitMask(pFlipped, dest_left, dest_top, abs(dest_width),
125 abs(dest_height), color, flags);
126 }
127
128 CFX_DIBExtractor temp(pSource);
129 RetainPtr<CFX_DIBitmap> pBitmap = temp.GetBitmap();
130 if (!pBitmap)
131 return false;
132 return GDI_StretchBitMask(pBitmap, dest_left, dest_top, dest_width,
133 dest_height, color, flags);
134 }
135
136 if (pSource->HasAlpha())
137 return false;
138
139 if (dest_width < 0 || dest_height < 0) {
140 RetainPtr<CFX_DIBitmap> pFlipped =
141 pSource->FlipImage(dest_width < 0, dest_height < 0);
142 if (!pFlipped)
143 return false;
144
145 if (dest_width < 0)
146 dest_left += dest_width;
147 if (dest_height < 0)
148 dest_top += dest_height;
149
150 return GDI_StretchDIBits(pFlipped, dest_left, dest_top, abs(dest_width),
151 abs(dest_height), flags);
152 }
153
154 CFX_DIBExtractor temp(pSource);
155 RetainPtr<CFX_DIBitmap> pBitmap = temp.GetBitmap();
156 if (!pBitmap)
157 return false;
158 return GDI_StretchDIBits(pBitmap, dest_left, dest_top, dest_width,
159 dest_height, flags);
160 }
161
StartDIBits(const RetainPtr<CFX_DIBSource> & pSource,int bitmap_alpha,uint32_t color,const CFX_Matrix * pMatrix,uint32_t render_flags,std::unique_ptr<CFX_ImageRenderer> * handle,int blend_type)162 bool CGdiPrinterDriver::StartDIBits(const RetainPtr<CFX_DIBSource>& pSource,
163 int bitmap_alpha,
164 uint32_t color,
165 const CFX_Matrix* pMatrix,
166 uint32_t render_flags,
167 std::unique_ptr<CFX_ImageRenderer>* handle,
168 int blend_type) {
169 if (bitmap_alpha < 255 || pSource->HasAlpha() ||
170 (pSource->IsAlphaMask() && (pSource->GetBPP() != 1))) {
171 return false;
172 }
173 CFX_FloatRect unit_rect = pMatrix->GetUnitRect();
174 FX_RECT full_rect = unit_rect.GetOuterRect();
175 if (fabs(pMatrix->b) < 0.5f && pMatrix->a != 0 && fabs(pMatrix->c) < 0.5f &&
176 pMatrix->d != 0) {
177 bool bFlipX = pMatrix->a < 0;
178 bool bFlipY = pMatrix->d > 0;
179 return StretchDIBits(pSource, color,
180 bFlipX ? full_rect.right : full_rect.left,
181 bFlipY ? full_rect.bottom : full_rect.top,
182 bFlipX ? -full_rect.Width() : full_rect.Width(),
183 bFlipY ? -full_rect.Height() : full_rect.Height(),
184 nullptr, 0, blend_type);
185 }
186 if (fabs(pMatrix->a) >= 0.5f || fabs(pMatrix->d) >= 0.5f)
187 return false;
188
189 RetainPtr<CFX_DIBitmap> pTransformed =
190 pSource->SwapXY(pMatrix->c > 0, pMatrix->b < 0);
191 if (!pTransformed)
192 return false;
193
194 return StretchDIBits(pTransformed, color, full_rect.left, full_rect.top,
195 full_rect.Width(), full_rect.Height(), nullptr, 0,
196 blend_type);
197 }
198
DrawDeviceText(int nChars,const FXTEXT_CHARPOS * pCharPos,CFX_Font * pFont,const CFX_Matrix * pObject2Device,float font_size,uint32_t color)199 bool CGdiPrinterDriver::DrawDeviceText(int nChars,
200 const FXTEXT_CHARPOS* pCharPos,
201 CFX_Font* pFont,
202 const CFX_Matrix* pObject2Device,
203 float font_size,
204 uint32_t color) {
205 #if defined(PDFIUM_PRINT_TEXT_WITH_GDI)
206 if (!g_pdfium_print_text_with_gdi)
207 return false;
208
209 if (nChars < 1 || !pFont || !pFont->IsEmbedded() || !pFont->IsTTFont())
210 return false;
211
212 // Scale factor used to minimize the kerning problems caused by rounding
213 // errors below. Value chosen based on the title of https://crbug.com/18383
214 const double kScaleFactor = 10;
215
216 // Font
217 //
218 // Note that |pFont| has the actual font to render with embedded within, but
219 // but unfortunately AddFontMemResourceEx() does not seem to cooperate.
220 // Loading font data to memory seems to work, but then enumerating the fonts
221 // fails to find it. This requires more investigation. In the meanwhile,
222 // assume the printing is happening on the machine that generated the PDF, so
223 // the embedded font, if not a web font, is available through GDI anyway.
224 // TODO(thestig): Figure out why AddFontMemResourceEx() does not work.
225 // Generalize this method to work for all PDFs with embedded fonts.
226 // In sandboxed environments, font loading may not work at all, so this may be
227 // the best possible effort.
228 LOGFONT lf = {};
229 lf.lfHeight = -font_size * kScaleFactor;
230 lf.lfWeight = pFont->IsBold() ? FW_BOLD : FW_NORMAL;
231 lf.lfItalic = pFont->IsItalic();
232 lf.lfCharSet = DEFAULT_CHARSET;
233
234 const WideString wsName = pFont->GetFaceName().UTF8Decode();
235 size_t iNameLen =
236 std::min(wsName.GetLength(), static_cast<size_t>(LF_FACESIZE - 1));
237 memcpy(lf.lfFaceName, wsName.c_str(), sizeof(lf.lfFaceName[0]) * iNameLen);
238 lf.lfFaceName[iNameLen] = 0;
239
240 HFONT hFont = CreateFontIndirect(&lf);
241 if (!hFont)
242 return false;
243
244 ScopedState state(m_hDC, hFont);
245 size_t nTextMetricSize = GetOutlineTextMetrics(m_hDC, 0, nullptr);
246 if (nTextMetricSize == 0) {
247 // Give up and fail if there is no way to get the font to try again.
248 if (!g_pdfium_typeface_accessible_func)
249 return false;
250
251 // Try to get the font. Any letter will do.
252 g_pdfium_typeface_accessible_func(&lf, L"A", 1);
253 nTextMetricSize = GetOutlineTextMetrics(m_hDC, 0, nullptr);
254 if (nTextMetricSize == 0)
255 return false;
256 }
257
258 std::vector<BYTE> buf(nTextMetricSize);
259 OUTLINETEXTMETRIC* pTextMetric =
260 reinterpret_cast<OUTLINETEXTMETRIC*>(buf.data());
261 if (GetOutlineTextMetrics(m_hDC, nTextMetricSize, pTextMetric) == 0)
262 return false;
263
264 // If the selected font is not the requested font, then bail out. This can
265 // happen with web fonts, for example.
266 wchar_t* wsSelectedName = reinterpret_cast<wchar_t*>(
267 buf.data() + reinterpret_cast<size_t>(pTextMetric->otmpFaceName));
268 if (wsName != wsSelectedName)
269 return false;
270
271 // Transforms
272 SetGraphicsMode(m_hDC, GM_ADVANCED);
273 XFORM xform;
274 xform.eM11 = pObject2Device->a / kScaleFactor;
275 xform.eM12 = pObject2Device->b / kScaleFactor;
276 xform.eM21 = -pObject2Device->c / kScaleFactor;
277 xform.eM22 = -pObject2Device->d / kScaleFactor;
278 xform.eDx = pObject2Device->e;
279 xform.eDy = pObject2Device->f;
280 ModifyWorldTransform(m_hDC, &xform, MWT_LEFTMULTIPLY);
281
282 // Color
283 int iUnusedAlpha;
284 FX_COLORREF rgb;
285 std::tie(iUnusedAlpha, rgb) = ArgbToColorRef(color);
286 SetTextColor(m_hDC, rgb);
287 SetBkMode(m_hDC, TRANSPARENT);
288
289 // Text
290 WideString wsText;
291 std::vector<INT> spacing(nChars);
292 float fPreviousOriginX = 0;
293 for (int i = 0; i < nChars; ++i) {
294 // Only works with PDFs from Skia's PDF generator. Cannot handle arbitrary
295 // values from PDFs.
296 const FXTEXT_CHARPOS& charpos = pCharPos[i];
297 ASSERT(charpos.m_AdjustMatrix[0] == 0);
298 ASSERT(charpos.m_AdjustMatrix[1] == 0);
299 ASSERT(charpos.m_AdjustMatrix[2] == 0);
300 ASSERT(charpos.m_AdjustMatrix[3] == 0);
301 ASSERT(charpos.m_Origin.y == 0);
302
303 // Round the spacing to the nearest integer, but keep track of the rounding
304 // error for calculating the next spacing value.
305 float fOriginX = charpos.m_Origin.x * kScaleFactor;
306 float fPixelSpacing = fOriginX - fPreviousOriginX;
307 spacing[i] = FXSYS_round(fPixelSpacing);
308 fPreviousOriginX = fOriginX - (fPixelSpacing - spacing[i]);
309
310 wsText += charpos.m_GlyphIndex;
311 }
312
313 // Draw
314 SetTextAlign(m_hDC, TA_LEFT | TA_BASELINE);
315 if (ExtTextOutW(m_hDC, 0, 0, ETO_GLYPH_INDEX, nullptr, wsText.c_str(), nChars,
316 nChars > 1 ? &spacing[1] : nullptr)) {
317 return true;
318 }
319
320 // Give up and fail if there is no way to get the font to try again.
321 if (!g_pdfium_typeface_accessible_func)
322 return false;
323
324 // Try to get the font and draw again.
325 g_pdfium_typeface_accessible_func(&lf, wsText.c_str(), nChars);
326 return !!ExtTextOutW(m_hDC, 0, 0, ETO_GLYPH_INDEX, nullptr, wsText.c_str(),
327 nChars, nChars > 1 ? &spacing[1] : nullptr);
328 #else
329 return false;
330 #endif
331 }
332
CPSPrinterDriver(HDC hDC,int pslevel,bool bCmykOutput)333 CPSPrinterDriver::CPSPrinterDriver(HDC hDC, int pslevel, bool bCmykOutput)
334 : m_hDC(hDC), m_bCmykOutput(bCmykOutput) {
335 m_HorzSize = ::GetDeviceCaps(m_hDC, HORZSIZE);
336 m_VertSize = ::GetDeviceCaps(m_hDC, VERTSIZE);
337 m_Width = ::GetDeviceCaps(m_hDC, HORZRES);
338 m_Height = ::GetDeviceCaps(m_hDC, VERTRES);
339 m_nBitsPerPixel = ::GetDeviceCaps(m_hDC, BITSPIXEL);
340
341 m_PSRenderer.Init(pdfium::MakeRetain<CPSOutput>(m_hDC), pslevel, m_Width,
342 m_Height, bCmykOutput);
343 HRGN hRgn = ::CreateRectRgn(0, 0, 1, 1);
344 int ret = ::GetClipRgn(hDC, hRgn);
345 if (ret == 1) {
346 ret = ::GetRegionData(hRgn, 0, NULL);
347 if (ret) {
348 RGNDATA* pData = reinterpret_cast<RGNDATA*>(FX_Alloc(uint8_t, ret));
349 ret = ::GetRegionData(hRgn, ret, pData);
350 if (ret) {
351 CFX_PathData path;
352 for (uint32_t i = 0; i < pData->rdh.nCount; i++) {
353 RECT* pRect =
354 reinterpret_cast<RECT*>(pData->Buffer + pData->rdh.nRgnSize * i);
355 path.AppendRect(static_cast<float>(pRect->left),
356 static_cast<float>(pRect->bottom),
357 static_cast<float>(pRect->right),
358 static_cast<float>(pRect->top));
359 }
360 m_PSRenderer.SetClip_PathFill(&path, nullptr, FXFILL_WINDING);
361 }
362 FX_Free(pData);
363 }
364 }
365 ::DeleteObject(hRgn);
366 }
367
~CPSPrinterDriver()368 CPSPrinterDriver::~CPSPrinterDriver() {
369 EndRendering();
370 }
371
GetDeviceCaps(int caps_id) const372 int CPSPrinterDriver::GetDeviceCaps(int caps_id) const {
373 switch (caps_id) {
374 case FXDC_DEVICE_CLASS:
375 return FXDC_PRINTER;
376 case FXDC_PIXEL_WIDTH:
377 return m_Width;
378 case FXDC_PIXEL_HEIGHT:
379 return m_Height;
380 case FXDC_BITS_PIXEL:
381 return m_nBitsPerPixel;
382 case FXDC_RENDER_CAPS:
383 return m_bCmykOutput ? FXRC_BIT_MASK | FXRC_CMYK_OUTPUT : FXRC_BIT_MASK;
384 case FXDC_HORZ_SIZE:
385 return m_HorzSize;
386 case FXDC_VERT_SIZE:
387 return m_VertSize;
388 }
389 return 0;
390 }
391
StartRendering()392 bool CPSPrinterDriver::StartRendering() {
393 return m_PSRenderer.StartRendering();
394 }
395
EndRendering()396 void CPSPrinterDriver::EndRendering() {
397 m_PSRenderer.EndRendering();
398 }
399
SaveState()400 void CPSPrinterDriver::SaveState() {
401 m_PSRenderer.SaveState();
402 }
403
RestoreState(bool bKeepSaved)404 void CPSPrinterDriver::RestoreState(bool bKeepSaved) {
405 m_PSRenderer.RestoreState(bKeepSaved);
406 }
407
SetClip_PathFill(const CFX_PathData * pPathData,const CFX_Matrix * pObject2Device,int fill_mode)408 bool CPSPrinterDriver::SetClip_PathFill(const CFX_PathData* pPathData,
409 const CFX_Matrix* pObject2Device,
410 int fill_mode) {
411 m_PSRenderer.SetClip_PathFill(pPathData, pObject2Device, fill_mode);
412 return true;
413 }
414
SetClip_PathStroke(const CFX_PathData * pPathData,const CFX_Matrix * pObject2Device,const CFX_GraphStateData * pGraphState)415 bool CPSPrinterDriver::SetClip_PathStroke(
416 const CFX_PathData* pPathData,
417 const CFX_Matrix* pObject2Device,
418 const CFX_GraphStateData* pGraphState) {
419 m_PSRenderer.SetClip_PathStroke(pPathData, pObject2Device, pGraphState);
420 return true;
421 }
422
DrawPath(const CFX_PathData * pPathData,const CFX_Matrix * pObject2Device,const CFX_GraphStateData * pGraphState,FX_ARGB fill_color,FX_ARGB stroke_color,int fill_mode,int blend_type)423 bool CPSPrinterDriver::DrawPath(const CFX_PathData* pPathData,
424 const CFX_Matrix* pObject2Device,
425 const CFX_GraphStateData* pGraphState,
426 FX_ARGB fill_color,
427 FX_ARGB stroke_color,
428 int fill_mode,
429 int blend_type) {
430 if (blend_type != FXDIB_BLEND_NORMAL) {
431 return false;
432 }
433 return m_PSRenderer.DrawPath(pPathData, pObject2Device, pGraphState,
434 fill_color, stroke_color, fill_mode & 3);
435 }
436
GetClipBox(FX_RECT * pRect)437 bool CPSPrinterDriver::GetClipBox(FX_RECT* pRect) {
438 *pRect = m_PSRenderer.GetClipBox();
439 return true;
440 }
441
SetDIBits(const RetainPtr<CFX_DIBSource> & pBitmap,uint32_t color,const FX_RECT * pSrcRect,int left,int top,int blend_type)442 bool CPSPrinterDriver::SetDIBits(const RetainPtr<CFX_DIBSource>& pBitmap,
443 uint32_t color,
444 const FX_RECT* pSrcRect,
445 int left,
446 int top,
447 int blend_type) {
448 if (blend_type != FXDIB_BLEND_NORMAL)
449 return false;
450 return m_PSRenderer.SetDIBits(pBitmap, color, left, top);
451 }
452
StretchDIBits(const RetainPtr<CFX_DIBSource> & pBitmap,uint32_t color,int dest_left,int dest_top,int dest_width,int dest_height,const FX_RECT * pClipRect,uint32_t flags,int blend_type)453 bool CPSPrinterDriver::StretchDIBits(const RetainPtr<CFX_DIBSource>& pBitmap,
454 uint32_t color,
455 int dest_left,
456 int dest_top,
457 int dest_width,
458 int dest_height,
459 const FX_RECT* pClipRect,
460 uint32_t flags,
461 int blend_type) {
462 if (blend_type != FXDIB_BLEND_NORMAL)
463 return false;
464 return m_PSRenderer.StretchDIBits(pBitmap, color, dest_left, dest_top,
465 dest_width, dest_height, flags);
466 }
467
StartDIBits(const RetainPtr<CFX_DIBSource> & pBitmap,int bitmap_alpha,uint32_t color,const CFX_Matrix * pMatrix,uint32_t render_flags,std::unique_ptr<CFX_ImageRenderer> * handle,int blend_type)468 bool CPSPrinterDriver::StartDIBits(const RetainPtr<CFX_DIBSource>& pBitmap,
469 int bitmap_alpha,
470 uint32_t color,
471 const CFX_Matrix* pMatrix,
472 uint32_t render_flags,
473 std::unique_ptr<CFX_ImageRenderer>* handle,
474 int blend_type) {
475 if (blend_type != FXDIB_BLEND_NORMAL)
476 return false;
477
478 if (bitmap_alpha < 255)
479 return false;
480
481 *handle = nullptr;
482 return m_PSRenderer.DrawDIBits(pBitmap, color, pMatrix, render_flags);
483 }
484
DrawDeviceText(int nChars,const FXTEXT_CHARPOS * pCharPos,CFX_Font * pFont,const CFX_Matrix * pObject2Device,float font_size,uint32_t color)485 bool CPSPrinterDriver::DrawDeviceText(int nChars,
486 const FXTEXT_CHARPOS* pCharPos,
487 CFX_Font* pFont,
488 const CFX_Matrix* pObject2Device,
489 float font_size,
490 uint32_t color) {
491 return m_PSRenderer.DrawText(nChars, pCharPos, pFont, pObject2Device,
492 font_size, color);
493 }
494
CTextOnlyPrinterDriver(HDC hDC)495 CTextOnlyPrinterDriver::CTextOnlyPrinterDriver(HDC hDC)
496 : m_hDC(hDC),
497 m_Width(INT_MAX),
498 m_Height(INT_MAX),
499 m_HorzSize(INT_MAX),
500 m_VertSize(INT_MAX),
501 m_OriginY(0.0f),
502 m_SetOrigin(false) {
503 m_nBitsPerPixel = ::GetDeviceCaps(m_hDC, BITSPIXEL);
504 }
505
~CTextOnlyPrinterDriver()506 CTextOnlyPrinterDriver::~CTextOnlyPrinterDriver() {
507 EndRendering();
508 }
509
GetDeviceCaps(int caps_id) const510 int CTextOnlyPrinterDriver::GetDeviceCaps(int caps_id) const {
511 switch (caps_id) {
512 case FXDC_DEVICE_CLASS:
513 return FXDC_PRINTER;
514 case FXDC_PIXEL_WIDTH:
515 return m_Width;
516 case FXDC_PIXEL_HEIGHT:
517 return m_Height;
518 case FXDC_BITS_PIXEL:
519 return m_nBitsPerPixel;
520 case FXDC_RENDER_CAPS:
521 return 0;
522 case FXDC_HORZ_SIZE:
523 return m_HorzSize;
524 case FXDC_VERT_SIZE:
525 return m_VertSize;
526 }
527 return 0;
528 }
529
SetClip_PathFill(const CFX_PathData * pPathData,const CFX_Matrix * pObject2Device,int fill_mode)530 bool CTextOnlyPrinterDriver::SetClip_PathFill(const CFX_PathData* pPathData,
531 const CFX_Matrix* pObject2Device,
532 int fill_mode) {
533 return true;
534 }
535
SetClip_PathStroke(const CFX_PathData * pPathData,const CFX_Matrix * pObject2Device,const CFX_GraphStateData * pGraphState)536 bool CTextOnlyPrinterDriver::SetClip_PathStroke(
537 const CFX_PathData* pPathData,
538 const CFX_Matrix* pObject2Device,
539 const CFX_GraphStateData* pGraphState) {
540 return false;
541 }
542
DrawPath(const CFX_PathData * pPathData,const CFX_Matrix * pObject2Device,const CFX_GraphStateData * pGraphState,uint32_t fill_color,uint32_t stroke_color,int fill_mode,int blend_type)543 bool CTextOnlyPrinterDriver::DrawPath(const CFX_PathData* pPathData,
544 const CFX_Matrix* pObject2Device,
545 const CFX_GraphStateData* pGraphState,
546 uint32_t fill_color,
547 uint32_t stroke_color,
548 int fill_mode,
549 int blend_type) {
550 return false;
551 }
552
SetDIBits(const RetainPtr<CFX_DIBSource> & pBitmap,uint32_t color,const FX_RECT * pSrcRect,int left,int top,int blend_type)553 bool CTextOnlyPrinterDriver::SetDIBits(const RetainPtr<CFX_DIBSource>& pBitmap,
554 uint32_t color,
555 const FX_RECT* pSrcRect,
556 int left,
557 int top,
558 int blend_type) {
559 return false;
560 }
561
GetClipBox(FX_RECT * pRect)562 bool CTextOnlyPrinterDriver::GetClipBox(FX_RECT* pRect) {
563 pRect->left = 0;
564 pRect->right = m_Width;
565 pRect->top = 0;
566 pRect->bottom = m_Height;
567 return true;
568 }
569
StretchDIBits(const RetainPtr<CFX_DIBSource> & pBitmap,uint32_t color,int dest_left,int dest_top,int dest_width,int dest_height,const FX_RECT * pClipRect,uint32_t flags,int blend_type)570 bool CTextOnlyPrinterDriver::StretchDIBits(
571 const RetainPtr<CFX_DIBSource>& pBitmap,
572 uint32_t color,
573 int dest_left,
574 int dest_top,
575 int dest_width,
576 int dest_height,
577 const FX_RECT* pClipRect,
578 uint32_t flags,
579 int blend_type) {
580 return false;
581 }
582
StartDIBits(const RetainPtr<CFX_DIBSource> & pBitmap,int bitmap_alpha,uint32_t color,const CFX_Matrix * pMatrix,uint32_t render_flags,std::unique_ptr<CFX_ImageRenderer> * handle,int blend_type)583 bool CTextOnlyPrinterDriver::StartDIBits(
584 const RetainPtr<CFX_DIBSource>& pBitmap,
585 int bitmap_alpha,
586 uint32_t color,
587 const CFX_Matrix* pMatrix,
588 uint32_t render_flags,
589 std::unique_ptr<CFX_ImageRenderer>* handle,
590 int blend_type) {
591 return false;
592 }
593
DrawDeviceText(int nChars,const FXTEXT_CHARPOS * pCharPos,CFX_Font * pFont,const CFX_Matrix * pObject2Device,float font_size,uint32_t color)594 bool CTextOnlyPrinterDriver::DrawDeviceText(int nChars,
595 const FXTEXT_CHARPOS* pCharPos,
596 CFX_Font* pFont,
597 const CFX_Matrix* pObject2Device,
598 float font_size,
599 uint32_t color) {
600 if (g_pdfium_print_mode != 1)
601 return false;
602 if (nChars < 1 || !pFont || !pFont->IsEmbedded() || !pFont->IsTTFont())
603 return false;
604
605 // Scale factor used to minimize the kerning problems caused by rounding
606 // errors below. Value chosen based on the title of https://crbug.com/18383
607 const double kScaleFactor = 10;
608
609 WideString wsText;
610 int totalLength = nChars;
611
612 // Detect new lines and add clrf characters (since this is Windows only).
613 // These characters are removed by SkPDF, but the new line information is
614 // preserved in the text location. clrf characters seem to be ignored by
615 // label printers that use this driver.
616 if (m_SetOrigin &&
617 FXSYS_round(m_OriginY) != FXSYS_round(pObject2Device->f * kScaleFactor)) {
618 wsText += L"\r\n";
619 totalLength += 2;
620 }
621 m_OriginY = pObject2Device->f * kScaleFactor;
622 m_SetOrigin = true;
623
624 // Text
625 for (int i = 0; i < nChars; ++i) {
626 // Only works with PDFs from Skia's PDF generator. Cannot handle arbitrary
627 // values from PDFs.
628 const FXTEXT_CHARPOS& charpos = pCharPos[i];
629 ASSERT(charpos.m_AdjustMatrix[0] == 0);
630 ASSERT(charpos.m_AdjustMatrix[1] == 0);
631 ASSERT(charpos.m_AdjustMatrix[2] == 0);
632 ASSERT(charpos.m_AdjustMatrix[3] == 0);
633 ASSERT(charpos.m_Origin.y == 0);
634
635 wsText += charpos.m_Unicode;
636 }
637 size_t len = totalLength;
638 ByteString text = ByteString::FromUnicode(wsText);
639 while (len > 0) {
640 char buffer[1026];
641 size_t send_len = std::min(len, static_cast<size_t>(1024));
642 *(reinterpret_cast<uint16_t*>(buffer)) = send_len;
643 memcpy(buffer + 2, text.c_str(), send_len);
644 ::GdiComment(m_hDC, send_len + 2, reinterpret_cast<const BYTE*>(buffer));
645 len -= send_len;
646 text.Right(len);
647 }
648 return true;
649 }
650