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 <crtdbg.h>
8
9 #include <algorithm>
10 #include <memory>
11 #include <vector>
12
13 #include "core/fxcrt/fx_codepage.h"
14 #include "core/fxcrt/fx_memory.h"
15 #include "core/fxcrt/fx_system.h"
16 #include "core/fxcrt/maybe_owned.h"
17 #include "core/fxge/cfx_folderfontinfo.h"
18 #include "core/fxge/cfx_fontmgr.h"
19 #include "core/fxge/cfx_gemodule.h"
20 #include "core/fxge/cfx_windowsrenderdevice.h"
21 #include "core/fxge/dib/cfx_dibextractor.h"
22 #include "core/fxge/dib/cfx_imagerenderer.h"
23 #include "core/fxge/dib/cstretchengine.h"
24 #include "core/fxge/fx_font.h"
25 #include "core/fxge/fx_freetype.h"
26 #include "core/fxge/systemfontinfo_iface.h"
27 #include "core/fxge/win32/cfx_windowsdib.h"
28 #include "core/fxge/win32/win32_int.h"
29 #include "third_party/base/ptr_util.h"
30 #include "third_party/base/span.h"
31 #include "third_party/base/win/win_util.h"
32
33 #ifndef _SKIA_SUPPORT_
34 #include "core/fxge/agg/fx_agg_driver.h"
35 #endif
36
37 namespace {
38
39 const struct {
40 const char* m_pFaceName;
41 const char* m_pVariantName; // Note: UTF-16LE terminator required.
42 } g_VariantNames[] = {
43 {"DFKai-SB", "\x19\x6A\x77\x69\xD4\x9A\x00\x00"},
44 };
45
46 const struct {
47 const char* m_pName;
48 const char* m_pWinName;
49 bool m_bBold;
50 bool m_bItalic;
51 } g_Base14Substs[] = {
52 {"Courier", "Courier New", false, false},
53 {"Courier-Bold", "Courier New", true, false},
54 {"Courier-BoldOblique", "Courier New", true, true},
55 {"Courier-Oblique", "Courier New", false, true},
56 {"Helvetica", "Arial", false, false},
57 {"Helvetica-Bold", "Arial", true, false},
58 {"Helvetica-BoldOblique", "Arial", true, true},
59 {"Helvetica-Oblique", "Arial", false, true},
60 {"Times-Roman", "Times New Roman", false, false},
61 {"Times-Bold", "Times New Roman", true, false},
62 {"Times-BoldItalic", "Times New Roman", true, true},
63 {"Times-Italic", "Times New Roman", false, true},
64 };
65
66 struct FontNameMap {
67 const char* m_pSubFontName;
68 const char* m_pSrcFontName;
69 };
70 const FontNameMap g_JpFontNameMap[] = {
71 {"MS Mincho", "Heiseimin-W3"},
72 {"MS Gothic", "Jun101-Light"},
73 };
74
GetSubFontName(ByteString * name)75 bool GetSubFontName(ByteString* name) {
76 for (size_t i = 0; i < FX_ArraySize(g_JpFontNameMap); ++i) {
77 if (!FXSYS_stricmp(name->c_str(), g_JpFontNameMap[i].m_pSrcFontName)) {
78 *name = g_JpFontNameMap[i].m_pSubFontName;
79 return true;
80 }
81 }
82 return false;
83 }
84
CreateExtPen(const CFX_GraphStateData * pGraphState,const CFX_Matrix * pMatrix,uint32_t argb)85 HPEN CreateExtPen(const CFX_GraphStateData* pGraphState,
86 const CFX_Matrix* pMatrix,
87 uint32_t argb) {
88 ASSERT(pGraphState);
89
90 float scale = 1.0f;
91 if (pMatrix) {
92 scale = fabs(pMatrix->a) > fabs(pMatrix->b) ? fabs(pMatrix->a)
93 : fabs(pMatrix->b);
94 }
95 float width = std::max(scale * pGraphState->m_LineWidth, 1.0f);
96
97 uint32_t PenStyle = PS_GEOMETRIC;
98 if (!pGraphState->m_DashArray.empty())
99 PenStyle |= PS_USERSTYLE;
100 else
101 PenStyle |= PS_SOLID;
102
103 switch (pGraphState->m_LineCap) {
104 case CFX_GraphStateData::LineCapButt:
105 PenStyle |= PS_ENDCAP_FLAT;
106 break;
107 case CFX_GraphStateData::LineCapRound:
108 PenStyle |= PS_ENDCAP_ROUND;
109 break;
110 case CFX_GraphStateData::LineCapSquare:
111 PenStyle |= PS_ENDCAP_SQUARE;
112 break;
113 }
114 switch (pGraphState->m_LineJoin) {
115 case CFX_GraphStateData::LineJoinMiter:
116 PenStyle |= PS_JOIN_MITER;
117 break;
118 case CFX_GraphStateData::LineJoinRound:
119 PenStyle |= PS_JOIN_ROUND;
120 break;
121 case CFX_GraphStateData::LineJoinBevel:
122 PenStyle |= PS_JOIN_BEVEL;
123 break;
124 }
125
126 FX_COLORREF colorref = ArgbToColorRef(argb);
127 LOGBRUSH lb;
128 lb.lbColor = colorref;
129 lb.lbStyle = BS_SOLID;
130 lb.lbHatch = 0;
131 std::vector<uint32_t> dashes;
132 if (!pGraphState->m_DashArray.empty()) {
133 dashes.resize(pGraphState->m_DashArray.size());
134 for (size_t i = 0; i < pGraphState->m_DashArray.size(); i++) {
135 dashes[i] = FXSYS_roundf(
136 pMatrix ? pMatrix->TransformDistance(pGraphState->m_DashArray[i])
137 : pGraphState->m_DashArray[i]);
138 dashes[i] = std::max(dashes[i], 1U);
139 }
140 }
141 return ExtCreatePen(PenStyle, (DWORD)ceil(width), &lb,
142 pGraphState->m_DashArray.size(),
143 reinterpret_cast<const DWORD*>(dashes.data()));
144 }
145
CreateBrush(uint32_t argb)146 HBRUSH CreateBrush(uint32_t argb) {
147 return CreateSolidBrush(ArgbToColorRef(argb));
148 }
149
SetPathToDC(HDC hDC,const CFX_PathData * pPathData,const CFX_Matrix * pMatrix)150 void SetPathToDC(HDC hDC,
151 const CFX_PathData* pPathData,
152 const CFX_Matrix* pMatrix) {
153 BeginPath(hDC);
154
155 const std::vector<FX_PATHPOINT>& pPoints = pPathData->GetPoints();
156 for (size_t i = 0; i < pPoints.size(); i++) {
157 CFX_PointF pos = pPoints[i].m_Point;
158 if (pMatrix)
159 pos = pMatrix->Transform(pos);
160
161 CFX_Point screen(FXSYS_roundf(pos.x), FXSYS_roundf(pos.y));
162 FXPT_TYPE point_type = pPoints[i].m_Type;
163 if (point_type == FXPT_TYPE::MoveTo) {
164 MoveToEx(hDC, screen.x, screen.y, nullptr);
165 } else if (point_type == FXPT_TYPE::LineTo) {
166 if (pPoints[i].m_Point == pPoints[i - 1].m_Point)
167 screen.x++;
168
169 LineTo(hDC, screen.x, screen.y);
170 } else if (point_type == FXPT_TYPE::BezierTo) {
171 POINT lppt[3];
172 lppt[0].x = screen.x;
173 lppt[0].y = screen.y;
174
175 pos = pPoints[i + 1].m_Point;
176 if (pMatrix)
177 pos = pMatrix->Transform(pos);
178
179 lppt[1].x = FXSYS_roundf(pos.x);
180 lppt[1].y = FXSYS_roundf(pos.y);
181
182 pos = pPoints[i + 2].m_Point;
183 if (pMatrix)
184 pos = pMatrix->Transform(pos);
185
186 lppt[2].x = FXSYS_roundf(pos.x);
187 lppt[2].y = FXSYS_roundf(pos.y);
188 PolyBezierTo(hDC, lppt, 3);
189 i += 2;
190 }
191 if (pPoints[i].m_CloseFigure)
192 CloseFigure(hDC);
193 }
194 EndPath(hDC);
195 }
196
197 #ifdef _SKIA_SUPPORT_
198 // TODO(caryclark) This antigrain function is duplicated here to permit
199 // removing the last remaining dependency. Eventually, this will be elminiated
200 // altogether and replace by Skia code.
201
202 struct rect_base {
203 float x1;
204 float y1;
205 float x2;
206 float y2;
207 };
208
clip_liang_barsky(float x1,float y1,float x2,float y2,const rect_base & clip_box,float * x,float * y)209 unsigned clip_liang_barsky(float x1,
210 float y1,
211 float x2,
212 float y2,
213 const rect_base& clip_box,
214 float* x,
215 float* y) {
216 const float nearzero = 1e-30f;
217 float deltax = x2 - x1;
218 float deltay = y2 - y1;
219 unsigned np = 0;
220 if (deltax == 0)
221 deltax = (x1 > clip_box.x1) ? -nearzero : nearzero;
222 float xin, xout;
223 if (deltax > 0) {
224 xin = clip_box.x1;
225 xout = clip_box.x2;
226 } else {
227 xin = clip_box.x2;
228 xout = clip_box.x1;
229 }
230 float tinx = (xin - x1) / deltax;
231 if (deltay == 0)
232 deltay = (y1 > clip_box.y1) ? -nearzero : nearzero;
233 float yin, yout;
234 if (deltay > 0) {
235 yin = clip_box.y1;
236 yout = clip_box.y2;
237 } else {
238 yin = clip_box.y2;
239 yout = clip_box.y1;
240 }
241 float tiny = (yin - y1) / deltay;
242 float tin1, tin2;
243 if (tinx < tiny) {
244 tin1 = tinx;
245 tin2 = tiny;
246 } else {
247 tin1 = tiny;
248 tin2 = tinx;
249 }
250 if (tin1 <= 1.0f) {
251 if (0 < tin1) {
252 *x++ = xin;
253 *y++ = yin;
254 ++np;
255 }
256 if (tin2 <= 1.0f) {
257 float toutx = (xout - x1) / deltax;
258 float touty = (yout - y1) / deltay;
259 float tout1 = (toutx < touty) ? toutx : touty;
260 if (tin2 > 0 || tout1 > 0) {
261 if (tin2 <= tout1) {
262 if (tin2 > 0) {
263 if (tinx > tiny) {
264 *x++ = xin;
265 *y++ = y1 + (deltay * tinx);
266 } else {
267 *x++ = x1 + (deltax * tiny);
268 *y++ = yin;
269 }
270 ++np;
271 }
272 if (tout1 < 1.0f) {
273 if (toutx < touty) {
274 *x++ = xout;
275 *y++ = y1 + (deltay * toutx);
276 } else {
277 *x++ = x1 + (deltax * touty);
278 *y++ = yout;
279 }
280 } else {
281 *x++ = x2;
282 *y++ = y2;
283 }
284 ++np;
285 } else {
286 if (tinx > tiny) {
287 *x++ = xin;
288 *y++ = yout;
289 } else {
290 *x++ = xout;
291 *y++ = yin;
292 }
293 ++np;
294 }
295 }
296 }
297 }
298 return np;
299 }
300 #endif // _SKIA_SUPPORT_
301
302 class CFX_Win32FallbackFontInfo final : public CFX_FolderFontInfo {
303 public:
304 CFX_Win32FallbackFontInfo() = default;
305 ~CFX_Win32FallbackFontInfo() override = default;
306
307 // CFX_FolderFontInfo:
308 void* MapFont(int weight,
309 bool bItalic,
310 int charset,
311 int pitch_family,
312 const char* family) override;
313 };
314
315 class CFX_Win32FontInfo final : public SystemFontInfoIface {
316 public:
317 CFX_Win32FontInfo();
318 ~CFX_Win32FontInfo() override;
319
320 // SystemFontInfoIface
321 bool EnumFontList(CFX_FontMapper* pMapper) override;
322 void* MapFont(int weight,
323 bool bItalic,
324 int charset,
325 int pitch_family,
326 const char* face) override;
GetFont(const char * face)327 void* GetFont(const char* face) override { return nullptr; }
328 uint32_t GetFontData(void* hFont,
329 uint32_t table,
330 pdfium::span<uint8_t> buffer) override;
331 bool GetFaceName(void* hFont, ByteString* name) override;
332 bool GetFontCharset(void* hFont, int* charset) override;
333 void DeleteFont(void* hFont) override;
334
335 bool IsOpenTypeFromDiv(const LOGFONTA* plf);
336 bool IsSupportFontFormDiv(const LOGFONTA* plf);
337 void AddInstalledFont(const LOGFONTA* plf, uint32_t FontType);
338 void GetGBPreference(ByteString& face, int weight, int picth_family);
339 void GetJapanesePreference(ByteString& face, int weight, int picth_family);
340 ByteString FindFont(const ByteString& name);
341
342 const HDC m_hDC;
343 UnownedPtr<CFX_FontMapper> m_pMapper;
344 ByteString m_LastFamily;
345 ByteString m_KaiTi;
346 ByteString m_FangSong;
347 };
348
FontEnumProc(const LOGFONTA * plf,const TEXTMETRICA * lpntme,uint32_t FontType,LPARAM lParam)349 int CALLBACK FontEnumProc(const LOGFONTA* plf,
350 const TEXTMETRICA* lpntme,
351 uint32_t FontType,
352 LPARAM lParam) {
353 CFX_Win32FontInfo* pFontInfo = reinterpret_cast<CFX_Win32FontInfo*>(lParam);
354 pFontInfo->AddInstalledFont(plf, FontType);
355 return 1;
356 }
357
CFX_Win32FontInfo()358 CFX_Win32FontInfo::CFX_Win32FontInfo() : m_hDC(CreateCompatibleDC(nullptr)) {}
359
~CFX_Win32FontInfo()360 CFX_Win32FontInfo::~CFX_Win32FontInfo() {
361 DeleteDC(m_hDC);
362 }
363
IsOpenTypeFromDiv(const LOGFONTA * plf)364 bool CFX_Win32FontInfo::IsOpenTypeFromDiv(const LOGFONTA* plf) {
365 HFONT hFont = CreateFontIndirectA(plf);
366 bool ret = false;
367 uint32_t font_size = GetFontData(hFont, 0, {});
368 if (font_size != GDI_ERROR && font_size >= sizeof(uint32_t)) {
369 uint32_t lVersion = 0;
370 GetFontData(hFont, 0, {(uint8_t*)(&lVersion), sizeof(uint32_t)});
371 lVersion = (((uint32_t)(uint8_t)(lVersion)) << 24) |
372 ((uint32_t)((uint8_t)(lVersion >> 8))) << 16 |
373 ((uint32_t)((uint8_t)(lVersion >> 16))) << 8 |
374 ((uint8_t)(lVersion >> 24));
375 if (lVersion == FXBSTR_ID('O', 'T', 'T', 'O') || lVersion == 0x00010000 ||
376 lVersion == FXBSTR_ID('t', 't', 'c', 'f') ||
377 lVersion == FXBSTR_ID('t', 'r', 'u', 'e') || lVersion == 0x00020000) {
378 ret = true;
379 }
380 }
381 DeleteFont(hFont);
382 return ret;
383 }
384
IsSupportFontFormDiv(const LOGFONTA * plf)385 bool CFX_Win32FontInfo::IsSupportFontFormDiv(const LOGFONTA* plf) {
386 HFONT hFont = CreateFontIndirectA(plf);
387 bool ret = false;
388 uint32_t font_size = GetFontData(hFont, 0, {});
389 if (font_size != GDI_ERROR && font_size >= sizeof(uint32_t)) {
390 uint32_t lVersion = 0;
391 GetFontData(hFont, 0, {(uint8_t*)(&lVersion), sizeof(lVersion)});
392 lVersion = (((uint32_t)(uint8_t)(lVersion)) << 24) |
393 ((uint32_t)((uint8_t)(lVersion >> 8))) << 16 |
394 ((uint32_t)((uint8_t)(lVersion >> 16))) << 8 |
395 ((uint8_t)(lVersion >> 24));
396 if (lVersion == FXBSTR_ID('O', 'T', 'T', 'O') || lVersion == 0x00010000 ||
397 lVersion == FXBSTR_ID('t', 't', 'c', 'f') ||
398 lVersion == FXBSTR_ID('t', 'r', 'u', 'e') || lVersion == 0x00020000 ||
399 (lVersion & 0xFFFF0000) == FXBSTR_ID(0x80, 0x01, 0x00, 0x00) ||
400 (lVersion & 0xFFFF0000) == FXBSTR_ID('%', '!', 0, 0)) {
401 ret = true;
402 }
403 }
404 DeleteFont(hFont);
405 return ret;
406 }
407
AddInstalledFont(const LOGFONTA * plf,uint32_t FontType)408 void CFX_Win32FontInfo::AddInstalledFont(const LOGFONTA* plf,
409 uint32_t FontType) {
410 ByteString name(plf->lfFaceName);
411 if (name.GetLength() > 0 && name[0] == '@')
412 return;
413
414 if (name == m_LastFamily) {
415 m_pMapper->AddInstalledFont(name, plf->lfCharSet);
416 return;
417 }
418 if (!(FontType & TRUETYPE_FONTTYPE)) {
419 if (!(FontType & DEVICE_FONTTYPE) || !IsSupportFontFormDiv(plf))
420 return;
421 }
422
423 m_pMapper->AddInstalledFont(name, plf->lfCharSet);
424 m_LastFamily = name;
425 }
426
EnumFontList(CFX_FontMapper * pMapper)427 bool CFX_Win32FontInfo::EnumFontList(CFX_FontMapper* pMapper) {
428 m_pMapper = pMapper;
429 LOGFONTA lf;
430 memset(&lf, 0, sizeof(LOGFONTA));
431 lf.lfCharSet = FX_CHARSET_Default;
432 lf.lfFaceName[0] = 0;
433 lf.lfPitchAndFamily = 0;
434 EnumFontFamiliesExA(m_hDC, &lf, (FONTENUMPROCA)FontEnumProc, (uintptr_t)this,
435 0);
436 return true;
437 }
438
FindFont(const ByteString & name)439 ByteString CFX_Win32FontInfo::FindFont(const ByteString& name) {
440 if (!m_pMapper)
441 return name;
442
443 for (size_t i = 0; i < m_pMapper->m_InstalledTTFonts.size(); ++i) {
444 ByteString thisname = m_pMapper->m_InstalledTTFonts[i];
445 if (thisname.First(name.GetLength()) == name)
446 return m_pMapper->m_InstalledTTFonts[i];
447 }
448 for (size_t i = 0; i < m_pMapper->m_LocalizedTTFonts.size(); ++i) {
449 ByteString thisname = m_pMapper->m_LocalizedTTFonts[i].first;
450 if (thisname.First(name.GetLength()) == name)
451 return m_pMapper->m_LocalizedTTFonts[i].second;
452 }
453 return ByteString();
454 }
455
MapFont(int weight,bool bItalic,int charset,int pitch_family,const char * cstr_face)456 void* CFX_Win32FallbackFontInfo::MapFont(int weight,
457 bool bItalic,
458 int charset,
459 int pitch_family,
460 const char* cstr_face) {
461 void* font = GetSubstFont(cstr_face);
462 if (font)
463 return font;
464
465 bool bCJK = true;
466 switch (charset) {
467 case FX_CHARSET_ShiftJIS:
468 case FX_CHARSET_ChineseSimplified:
469 case FX_CHARSET_ChineseTraditional:
470 case FX_CHARSET_Hangul:
471 break;
472 default:
473 bCJK = false;
474 break;
475 }
476 return FindFont(weight, bItalic, charset, pitch_family, cstr_face, !bCJK);
477 }
478
GetGBPreference(ByteString & face,int weight,int picth_family)479 void CFX_Win32FontInfo::GetGBPreference(ByteString& face,
480 int weight,
481 int picth_family) {
482 if (face.Contains("KaiTi") || face.Contains("\xbf\xac")) {
483 if (m_KaiTi.IsEmpty()) {
484 m_KaiTi = FindFont("KaiTi");
485 if (m_KaiTi.IsEmpty()) {
486 m_KaiTi = "SimSun";
487 }
488 }
489 face = m_KaiTi;
490 } else if (face.Contains("FangSong") || face.Contains("\xb7\xc2\xcb\xce")) {
491 if (m_FangSong.IsEmpty()) {
492 m_FangSong = FindFont("FangSong");
493 if (m_FangSong.IsEmpty()) {
494 m_FangSong = "SimSun";
495 }
496 }
497 face = m_FangSong;
498 } else if (face.Contains("SimSun") || face.Contains("\xcb\xce")) {
499 face = "SimSun";
500 } else if (face.Contains("SimHei") || face.Contains("\xba\xda")) {
501 face = "SimHei";
502 } else if (!(picth_family & FF_ROMAN) && weight > 550) {
503 face = "SimHei";
504 } else {
505 face = "SimSun";
506 }
507 }
508
GetJapanesePreference(ByteString & face,int weight,int picth_family)509 void CFX_Win32FontInfo::GetJapanesePreference(ByteString& face,
510 int weight,
511 int picth_family) {
512 if (face.Contains("Gothic") ||
513 face.Contains("\x83\x53\x83\x56\x83\x62\x83\x4e")) {
514 if (face.Contains("PGothic") ||
515 face.Contains("\x82\x6f\x83\x53\x83\x56\x83\x62\x83\x4e")) {
516 face = "MS PGothic";
517 } else if (face.Contains("UI Gothic")) {
518 face = "MS UI Gothic";
519 } else {
520 if (face.Contains("HGSGothicM") || face.Contains("HGMaruGothicMPRO")) {
521 face = "MS PGothic";
522 } else {
523 face = "MS Gothic";
524 }
525 }
526 return;
527 }
528 if (face.Contains("Mincho") || face.Contains("\x96\xbe\x92\xa9")) {
529 if (face.Contains("PMincho") || face.Contains("\x82\x6f\x96\xbe\x92\xa9")) {
530 face = "MS PMincho";
531 } else {
532 face = "MS Mincho";
533 }
534 return;
535 }
536 if (GetSubFontName(&face))
537 return;
538
539 if (!(picth_family & FF_ROMAN) && weight > 400) {
540 face = "MS PGothic";
541 } else {
542 face = "MS PMincho";
543 }
544 }
545
MapFont(int weight,bool bItalic,int charset,int pitch_family,const char * cstr_face)546 void* CFX_Win32FontInfo::MapFont(int weight,
547 bool bItalic,
548 int charset,
549 int pitch_family,
550 const char* cstr_face) {
551 ByteString face = cstr_face;
552 int iBaseFont;
553 for (iBaseFont = 0; iBaseFont < 12; iBaseFont++) {
554 if (face == ByteStringView(g_Base14Substs[iBaseFont].m_pName)) {
555 face = g_Base14Substs[iBaseFont].m_pWinName;
556 weight = g_Base14Substs[iBaseFont].m_bBold ? FW_BOLD : FW_NORMAL;
557 bItalic = g_Base14Substs[iBaseFont].m_bItalic;
558 break;
559 }
560 }
561 if (charset == FX_CHARSET_ANSI || charset == FX_CHARSET_Symbol)
562 charset = FX_CHARSET_Default;
563
564 int subst_pitch_family = pitch_family;
565 switch (charset) {
566 case FX_CHARSET_ShiftJIS:
567 subst_pitch_family = FF_ROMAN;
568 break;
569 case FX_CHARSET_ChineseTraditional:
570 case FX_CHARSET_Hangul:
571 case FX_CHARSET_ChineseSimplified:
572 subst_pitch_family = 0;
573 break;
574 }
575 HFONT hFont =
576 ::CreateFontA(-10, 0, 0, 0, weight, bItalic, 0, 0, charset,
577 OUT_TT_ONLY_PRECIS, 0, 0, subst_pitch_family, face.c_str());
578 char facebuf[100];
579 HFONT hOldFont = (HFONT)::SelectObject(m_hDC, hFont);
580 ::GetTextFaceA(m_hDC, 100, facebuf);
581 ::SelectObject(m_hDC, hOldFont);
582 if (face.EqualNoCase(facebuf))
583 return hFont;
584
585 WideString wsFace = WideString::FromDefANSI(facebuf);
586 for (size_t i = 0; i < FX_ArraySize(g_VariantNames); ++i) {
587 if (face != g_VariantNames[i].m_pFaceName)
588 continue;
589
590 const unsigned short* pName = reinterpret_cast<const unsigned short*>(
591 g_VariantNames[i].m_pVariantName);
592 size_t len = WideString::WStringLength(pName);
593 WideString wsName = WideString::FromUTF16LE(pName, len);
594 if (wsFace == wsName)
595 return hFont;
596 }
597 ::DeleteObject(hFont);
598 if (charset == FX_CHARSET_Default)
599 return nullptr;
600
601 switch (charset) {
602 case FX_CHARSET_ShiftJIS:
603 GetJapanesePreference(face, weight, pitch_family);
604 break;
605 case FX_CHARSET_ChineseSimplified:
606 GetGBPreference(face, weight, pitch_family);
607 break;
608 case FX_CHARSET_Hangul:
609 face = "Gulim";
610 break;
611 case FX_CHARSET_ChineseTraditional:
612 if (face.Contains("MSung")) {
613 face = "MingLiU";
614 } else {
615 face = "PMingLiU";
616 }
617 break;
618 }
619 hFont =
620 ::CreateFontA(-10, 0, 0, 0, weight, bItalic, 0, 0, charset,
621 OUT_TT_ONLY_PRECIS, 0, 0, subst_pitch_family, face.c_str());
622 return hFont;
623 }
624
DeleteFont(void * hFont)625 void CFX_Win32FontInfo::DeleteFont(void* hFont) {
626 ::DeleteObject(hFont);
627 }
628
GetFontData(void * hFont,uint32_t table,pdfium::span<uint8_t> buffer)629 uint32_t CFX_Win32FontInfo::GetFontData(void* hFont,
630 uint32_t table,
631 pdfium::span<uint8_t> buffer) {
632 HFONT hOldFont = (HFONT)::SelectObject(m_hDC, (HFONT)hFont);
633 table = FXDWORD_GET_MSBFIRST(reinterpret_cast<uint8_t*>(&table));
634 uint32_t size = ::GetFontData(m_hDC, table, 0, buffer.data(), buffer.size());
635 ::SelectObject(m_hDC, hOldFont);
636 if (size == GDI_ERROR) {
637 return 0;
638 }
639 return size;
640 }
641
GetFaceName(void * hFont,ByteString * name)642 bool CFX_Win32FontInfo::GetFaceName(void* hFont, ByteString* name) {
643 char facebuf[100];
644 HFONT hOldFont = (HFONT)::SelectObject(m_hDC, (HFONT)hFont);
645 int ret = ::GetTextFaceA(m_hDC, 100, facebuf);
646 ::SelectObject(m_hDC, hOldFont);
647 if (ret == 0) {
648 return false;
649 }
650 *name = facebuf;
651 return true;
652 }
653
GetFontCharset(void * hFont,int * charset)654 bool CFX_Win32FontInfo::GetFontCharset(void* hFont, int* charset) {
655 TEXTMETRIC tm;
656 HFONT hOldFont = (HFONT)::SelectObject(m_hDC, (HFONT)hFont);
657 ::GetTextMetrics(m_hDC, &tm);
658 ::SelectObject(m_hDC, hOldFont);
659 *charset = tm.tmCharSet;
660 return true;
661 }
662
663 } // namespace
664
665 WindowsPrintMode g_pdfium_print_mode = WindowsPrintMode::kModeEmf;
666
CreateDefault(const char ** pUnused)667 std::unique_ptr<SystemFontInfoIface> SystemFontInfoIface::CreateDefault(
668 const char** pUnused) {
669 if (pdfium::base::win::IsUser32AndGdi32Available())
670 return std::unique_ptr<SystemFontInfoIface>(new CFX_Win32FontInfo);
671
672 // Select the fallback font information class if GDI is disabled.
673 CFX_Win32FallbackFontInfo* pInfoFallback = new CFX_Win32FallbackFontInfo;
674 // Construct the font path manually, SHGetKnownFolderPath won't work under
675 // a restrictive sandbox.
676 CHAR windows_path[MAX_PATH] = {};
677 DWORD path_len = ::GetWindowsDirectoryA(windows_path, MAX_PATH);
678 if (path_len > 0 && path_len < MAX_PATH) {
679 ByteString fonts_path(windows_path);
680 fonts_path += "\\Fonts";
681 pInfoFallback->AddPath(fonts_path);
682 }
683 return std::unique_ptr<SystemFontInfoIface>(pInfoFallback);
684 }
685
686 CWin32Platform::CWin32Platform() = default;
687
688 CWin32Platform::~CWin32Platform() = default;
689
Init()690 void CWin32Platform::Init() {
691 OSVERSIONINFO ver;
692 ver.dwOSVersionInfoSize = sizeof(ver);
693 GetVersionEx(&ver);
694 m_bHalfTone = ver.dwMajorVersion >= 5;
695 if (pdfium::base::win::IsUser32AndGdi32Available())
696 m_GdiplusExt.Load();
697 CFX_GEModule::Get()->GetFontMgr()->SetSystemFontInfo(
698 SystemFontInfoIface::CreateDefault(nullptr));
699 }
700
701 // static
702 std::unique_ptr<CFX_GEModule::PlatformIface>
Create()703 CFX_GEModule::PlatformIface::Create() {
704 return pdfium::MakeUnique<CWin32Platform>();
705 }
706
CGdiDeviceDriver(HDC hDC,DeviceType device_type)707 CGdiDeviceDriver::CGdiDeviceDriver(HDC hDC, DeviceType device_type)
708 : m_hDC(hDC), m_DeviceType(device_type) {
709 auto* pPlatform =
710 static_cast<CWin32Platform*>(CFX_GEModule::Get()->GetPlatform());
711 SetStretchBltMode(m_hDC, pPlatform->m_bHalfTone ? HALFTONE : COLORONCOLOR);
712 DWORD obj_type = GetObjectType(m_hDC);
713 m_bMetafileDCType = obj_type == OBJ_ENHMETADC || obj_type == OBJ_ENHMETAFILE;
714 if (obj_type == OBJ_MEMDC) {
715 HBITMAP hBitmap = CreateBitmap(1, 1, 1, 1, nullptr);
716 hBitmap = (HBITMAP)SelectObject(m_hDC, hBitmap);
717 BITMAP bitmap;
718 GetObject(hBitmap, sizeof bitmap, &bitmap);
719 m_nBitsPerPixel = bitmap.bmBitsPixel;
720 m_Width = bitmap.bmWidth;
721 m_Height = abs(bitmap.bmHeight);
722 hBitmap = (HBITMAP)SelectObject(m_hDC, hBitmap);
723 DeleteObject(hBitmap);
724 } else {
725 m_nBitsPerPixel = ::GetDeviceCaps(m_hDC, BITSPIXEL);
726 m_Width = ::GetDeviceCaps(m_hDC, HORZRES);
727 m_Height = ::GetDeviceCaps(m_hDC, VERTRES);
728 }
729 if (m_DeviceType != DeviceType::kDisplay) {
730 m_RenderCaps = FXRC_BIT_MASK;
731 } else {
732 m_RenderCaps = FXRC_GET_BITS | FXRC_BIT_MASK;
733 }
734 }
735
736 CGdiDeviceDriver::~CGdiDeviceDriver() = default;
737
GetDeviceType() const738 DeviceType CGdiDeviceDriver::GetDeviceType() const {
739 return m_DeviceType;
740 }
741
GetDeviceCaps(int caps_id) const742 int CGdiDeviceDriver::GetDeviceCaps(int caps_id) const {
743 switch (caps_id) {
744 case FXDC_PIXEL_WIDTH:
745 return m_Width;
746 case FXDC_PIXEL_HEIGHT:
747 return m_Height;
748 case FXDC_BITS_PIXEL:
749 return m_nBitsPerPixel;
750 case FXDC_RENDER_CAPS:
751 return m_RenderCaps;
752 default:
753 NOTREACHED();
754 return 0;
755 }
756 }
757
SaveState()758 void CGdiDeviceDriver::SaveState() {
759 SaveDC(m_hDC);
760 }
761
RestoreState(bool bKeepSaved)762 void CGdiDeviceDriver::RestoreState(bool bKeepSaved) {
763 RestoreDC(m_hDC, -1);
764 if (bKeepSaved)
765 SaveDC(m_hDC);
766 }
767
GDI_SetDIBits(const RetainPtr<CFX_DIBitmap> & pBitmap1,const FX_RECT & src_rect,int left,int top)768 bool CGdiDeviceDriver::GDI_SetDIBits(const RetainPtr<CFX_DIBitmap>& pBitmap1,
769 const FX_RECT& src_rect,
770 int left,
771 int top) {
772 if (m_DeviceType == DeviceType::kPrinter) {
773 RetainPtr<CFX_DIBitmap> pBitmap = pBitmap1->FlipImage(false, true);
774 if (!pBitmap)
775 return false;
776
777 if (pBitmap->IsCmykImage() && !pBitmap->ConvertFormat(FXDIB_Rgb))
778 return false;
779
780 LPBYTE pBuffer = pBitmap->GetBuffer();
781 ByteString info = CFX_WindowsDIB::GetBitmapInfo(pBitmap);
782 ((BITMAPINFOHEADER*)info.c_str())->biHeight *= -1;
783 FX_RECT dst_rect(0, 0, src_rect.Width(), src_rect.Height());
784 dst_rect.Intersect(0, 0, pBitmap->GetWidth(), pBitmap->GetHeight());
785 int dst_width = dst_rect.Width();
786 int dst_height = dst_rect.Height();
787 ::StretchDIBits(m_hDC, left, top, dst_width, dst_height, 0, 0, dst_width,
788 dst_height, pBuffer, (BITMAPINFO*)info.c_str(),
789 DIB_RGB_COLORS, SRCCOPY);
790 return true;
791 }
792
793 RetainPtr<CFX_DIBitmap> pBitmap = pBitmap1;
794 if (pBitmap->IsCmykImage()) {
795 pBitmap = pBitmap->CloneConvert(FXDIB_Rgb);
796 if (!pBitmap)
797 return false;
798 }
799 LPBYTE pBuffer = pBitmap->GetBuffer();
800 ByteString info = CFX_WindowsDIB::GetBitmapInfo(pBitmap);
801 ::SetDIBitsToDevice(m_hDC, left, top, src_rect.Width(), src_rect.Height(),
802 src_rect.left, pBitmap->GetHeight() - src_rect.bottom, 0,
803 pBitmap->GetHeight(), pBuffer, (BITMAPINFO*)info.c_str(),
804 DIB_RGB_COLORS);
805 return true;
806 }
807
GDI_StretchDIBits(const RetainPtr<CFX_DIBitmap> & pBitmap1,int dest_left,int dest_top,int dest_width,int dest_height,const FXDIB_ResampleOptions & options)808 bool CGdiDeviceDriver::GDI_StretchDIBits(
809 const RetainPtr<CFX_DIBitmap>& pBitmap1,
810 int dest_left,
811 int dest_top,
812 int dest_width,
813 int dest_height,
814 const FXDIB_ResampleOptions& options) {
815 RetainPtr<CFX_DIBitmap> pBitmap = pBitmap1;
816 if (!pBitmap || dest_width == 0 || dest_height == 0)
817 return false;
818
819 if (pBitmap->IsCmykImage() && !pBitmap->ConvertFormat(FXDIB_Rgb))
820 return false;
821
822 ByteString info = CFX_WindowsDIB::GetBitmapInfo(pBitmap);
823 if ((int64_t)abs(dest_width) * abs(dest_height) <
824 (int64_t)pBitmap1->GetWidth() * pBitmap1->GetHeight() * 4 ||
825 options.bInterpolateBilinear || options.bInterpolateBicubic) {
826 SetStretchBltMode(m_hDC, HALFTONE);
827 } else {
828 SetStretchBltMode(m_hDC, COLORONCOLOR);
829 }
830 RetainPtr<CFX_DIBitmap> pToStrechBitmap = pBitmap;
831 if (m_DeviceType == DeviceType::kPrinter &&
832 ((int64_t)pBitmap->GetWidth() * pBitmap->GetHeight() >
833 (int64_t)abs(dest_width) * abs(dest_height))) {
834 pToStrechBitmap = pBitmap->StretchTo(dest_width, dest_height,
835 FXDIB_ResampleOptions(), nullptr);
836 }
837 ByteString toStrechBitmapInfo =
838 CFX_WindowsDIB::GetBitmapInfo(pToStrechBitmap);
839 ::StretchDIBits(m_hDC, dest_left, dest_top, dest_width, dest_height, 0, 0,
840 pToStrechBitmap->GetWidth(), pToStrechBitmap->GetHeight(),
841 pToStrechBitmap->GetBuffer(),
842 (BITMAPINFO*)toStrechBitmapInfo.c_str(), DIB_RGB_COLORS,
843 SRCCOPY);
844 return true;
845 }
846
GDI_StretchBitMask(const RetainPtr<CFX_DIBitmap> & pBitmap1,int dest_left,int dest_top,int dest_width,int dest_height,uint32_t bitmap_color)847 bool CGdiDeviceDriver::GDI_StretchBitMask(
848 const RetainPtr<CFX_DIBitmap>& pBitmap1,
849 int dest_left,
850 int dest_top,
851 int dest_width,
852 int dest_height,
853 uint32_t bitmap_color) {
854 RetainPtr<CFX_DIBitmap> pBitmap = pBitmap1;
855 if (!pBitmap || dest_width == 0 || dest_height == 0)
856 return false;
857
858 int width = pBitmap->GetWidth(), height = pBitmap->GetHeight();
859 struct {
860 BITMAPINFOHEADER bmiHeader;
861 uint32_t bmiColors[2];
862 } bmi;
863 memset(&bmi.bmiHeader, 0, sizeof(BITMAPINFOHEADER));
864 bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
865 bmi.bmiHeader.biBitCount = 1;
866 bmi.bmiHeader.biCompression = BI_RGB;
867 bmi.bmiHeader.biHeight = -height;
868 bmi.bmiHeader.biPlanes = 1;
869 bmi.bmiHeader.biWidth = width;
870 if (m_nBitsPerPixel != 1) {
871 SetStretchBltMode(m_hDC, HALFTONE);
872 }
873 bmi.bmiColors[0] = 0xffffff;
874 bmi.bmiColors[1] = 0;
875
876 HBRUSH hPattern = CreateBrush(bitmap_color);
877 HBRUSH hOld = (HBRUSH)SelectObject(m_hDC, hPattern);
878
879 // In PDF, when image mask is 1, use device bitmap; when mask is 0, use brush
880 // bitmap.
881 // A complete list of the boolen operations is as follows:
882
883 /* P(bitmap_color) S(ImageMask) D(DeviceBitmap) Result
884 * 0 0 0 0
885 * 0 0 1 0
886 * 0 1 0 0
887 * 0 1 1 1
888 * 1 0 0 1
889 * 1 0 1 1
890 * 1 1 0 0
891 * 1 1 1 1
892 */
893 // The boolen codes is B8. Based on
894 // http://msdn.microsoft.com/en-us/library/aa932106.aspx, the ROP3 code is
895 // 0xB8074A
896
897 ::StretchDIBits(m_hDC, dest_left, dest_top, dest_width, dest_height, 0, 0,
898 width, height, pBitmap->GetBuffer(), (BITMAPINFO*)&bmi,
899 DIB_RGB_COLORS, 0xB8074A);
900
901 SelectObject(m_hDC, hOld);
902 DeleteObject(hPattern);
903
904 return true;
905 }
906
GetClipBox(FX_RECT * pRect)907 bool CGdiDeviceDriver::GetClipBox(FX_RECT* pRect) {
908 return !!(::GetClipBox(m_hDC, (RECT*)pRect));
909 }
910
DrawLine(float x1,float y1,float x2,float y2)911 void CGdiDeviceDriver::DrawLine(float x1, float y1, float x2, float y2) {
912 if (!m_bMetafileDCType) { // EMF drawing is not bound to the DC.
913 int startOutOfBoundsFlag = (x1 < 0) | ((x1 > m_Width) << 1) |
914 ((y1 < 0) << 2) | ((y1 > m_Height) << 3);
915 int endOutOfBoundsFlag = (x2 < 0) | ((x2 > m_Width) << 1) |
916 ((y2 < 0) << 2) | ((y2 > m_Height) << 3);
917 if (startOutOfBoundsFlag & endOutOfBoundsFlag)
918 return;
919
920 if (startOutOfBoundsFlag || endOutOfBoundsFlag) {
921 float x[2];
922 float y[2];
923 int np;
924 #ifdef _SKIA_SUPPORT_
925 // TODO(caryclark) temporary replacement of antigrain in line function
926 // to permit removing antigrain altogether
927 rect_base rect = {0.0f, 0.0f, (float)(m_Width), (float)(m_Height)};
928 np = clip_liang_barsky(x1, y1, x2, y2, rect, x, y);
929 #else
930 agg::rect_base<float> rect(0.0f, 0.0f, (float)(m_Width),
931 (float)(m_Height));
932 np = agg::clip_liang_barsky<float>(x1, y1, x2, y2, rect, x, y);
933 #endif
934 if (np == 0)
935 return;
936
937 if (np == 1) {
938 x2 = x[0];
939 y2 = y[0];
940 } else {
941 ASSERT(np == 2);
942 x1 = x[0];
943 y1 = y[0];
944 x2 = x[1];
945 y2 = y[1];
946 }
947 }
948 }
949
950 MoveToEx(m_hDC, FXSYS_roundf(x1), FXSYS_roundf(y1), nullptr);
951 LineTo(m_hDC, FXSYS_roundf(x2), FXSYS_roundf(y2));
952 }
953
DrawPath(const CFX_PathData * pPathData,const CFX_Matrix * pMatrix,const CFX_GraphStateData * pGraphState,uint32_t fill_color,uint32_t stroke_color,int fill_mode,BlendMode blend_type)954 bool CGdiDeviceDriver::DrawPath(const CFX_PathData* pPathData,
955 const CFX_Matrix* pMatrix,
956 const CFX_GraphStateData* pGraphState,
957 uint32_t fill_color,
958 uint32_t stroke_color,
959 int fill_mode,
960 BlendMode blend_type) {
961 if (blend_type != BlendMode::kNormal)
962 return false;
963
964 auto* pPlatform =
965 static_cast<CWin32Platform*>(CFX_GEModule::Get()->GetPlatform());
966 if (!(pGraphState || stroke_color == 0) &&
967 !pPlatform->m_GdiplusExt.IsAvailable()) {
968 CFX_FloatRect bbox_f = pPathData->GetBoundingBox();
969 if (pMatrix)
970 bbox_f = pMatrix->TransformRect(bbox_f);
971
972 FX_RECT bbox = bbox_f.GetInnerRect();
973 if (bbox.Width() <= 0) {
974 return DrawCosmeticLine(CFX_PointF(bbox.left, bbox.top),
975 CFX_PointF(bbox.left, bbox.bottom + 1),
976 fill_color, BlendMode::kNormal);
977 }
978 if (bbox.Height() <= 0) {
979 return DrawCosmeticLine(CFX_PointF(bbox.left, bbox.top),
980 CFX_PointF(bbox.right + 1, bbox.top), fill_color,
981 BlendMode::kNormal);
982 }
983 }
984 int fill_alpha = FXARGB_A(fill_color);
985 int stroke_alpha = FXARGB_A(stroke_color);
986 bool bDrawAlpha = (fill_alpha > 0 && fill_alpha < 255) ||
987 (stroke_alpha > 0 && stroke_alpha < 255 && pGraphState);
988 if (!pPlatform->m_GdiplusExt.IsAvailable() && bDrawAlpha)
989 return false;
990
991 if (pPlatform->m_GdiplusExt.IsAvailable()) {
992 if (bDrawAlpha || ((m_DeviceType != DeviceType::kPrinter &&
993 !(fill_mode & FXFILL_FULLCOVER)) ||
994 (pGraphState && !pGraphState->m_DashArray.empty()))) {
995 if (!((!pMatrix || !pMatrix->WillScale()) && pGraphState &&
996 pGraphState->m_LineWidth == 1.0f &&
997 (pPathData->GetPoints().size() == 5 ||
998 pPathData->GetPoints().size() == 4) &&
999 pPathData->IsRect())) {
1000 if (pPlatform->m_GdiplusExt.DrawPath(m_hDC, pPathData, pMatrix,
1001 pGraphState, fill_color,
1002 stroke_color, fill_mode)) {
1003 return true;
1004 }
1005 }
1006 }
1007 }
1008 int old_fill_mode = fill_mode;
1009 fill_mode &= 3;
1010 HPEN hPen = nullptr;
1011 HBRUSH hBrush = nullptr;
1012 if (pGraphState && stroke_alpha) {
1013 SetMiterLimit(m_hDC, pGraphState->m_MiterLimit, nullptr);
1014 hPen = CreateExtPen(pGraphState, pMatrix, stroke_color);
1015 hPen = (HPEN)SelectObject(m_hDC, hPen);
1016 }
1017 if (fill_mode && fill_alpha) {
1018 SetPolyFillMode(m_hDC, fill_mode);
1019 hBrush = CreateBrush(fill_color);
1020 hBrush = (HBRUSH)SelectObject(m_hDC, hBrush);
1021 }
1022 if (pPathData->GetPoints().size() == 2 && pGraphState &&
1023 !pGraphState->m_DashArray.empty()) {
1024 CFX_PointF pos1 = pPathData->GetPoint(0);
1025 CFX_PointF pos2 = pPathData->GetPoint(1);
1026 if (pMatrix) {
1027 pos1 = pMatrix->Transform(pos1);
1028 pos2 = pMatrix->Transform(pos2);
1029 }
1030 DrawLine(pos1.x, pos1.y, pos2.x, pos2.y);
1031 } else {
1032 SetPathToDC(m_hDC, pPathData, pMatrix);
1033 if (pGraphState && stroke_alpha) {
1034 if (fill_mode && fill_alpha) {
1035 if (old_fill_mode & FX_FILL_TEXT_MODE) {
1036 StrokeAndFillPath(m_hDC);
1037 } else {
1038 FillPath(m_hDC);
1039 SetPathToDC(m_hDC, pPathData, pMatrix);
1040 StrokePath(m_hDC);
1041 }
1042 } else {
1043 StrokePath(m_hDC);
1044 }
1045 } else if (fill_mode && fill_alpha) {
1046 FillPath(m_hDC);
1047 }
1048 }
1049 if (hPen) {
1050 hPen = (HPEN)SelectObject(m_hDC, hPen);
1051 DeleteObject(hPen);
1052 }
1053 if (hBrush) {
1054 hBrush = (HBRUSH)SelectObject(m_hDC, hBrush);
1055 DeleteObject(hBrush);
1056 }
1057 return true;
1058 }
1059
FillRectWithBlend(const FX_RECT & rect,uint32_t fill_color,BlendMode blend_type)1060 bool CGdiDeviceDriver::FillRectWithBlend(const FX_RECT& rect,
1061 uint32_t fill_color,
1062 BlendMode blend_type) {
1063 if (blend_type != BlendMode::kNormal)
1064 return false;
1065
1066 int alpha;
1067 FX_COLORREF colorref;
1068 std::tie(alpha, colorref) = ArgbToAlphaAndColorRef(fill_color);
1069 if (alpha == 0)
1070 return true;
1071
1072 if (alpha < 255)
1073 return false;
1074
1075 HBRUSH hBrush = CreateSolidBrush(colorref);
1076 const RECT* pRect = reinterpret_cast<const RECT*>(&rect);
1077 ::FillRect(m_hDC, pRect, hBrush);
1078 DeleteObject(hBrush);
1079 return true;
1080 }
1081
SetBaseClip(const FX_RECT & rect)1082 void CGdiDeviceDriver::SetBaseClip(const FX_RECT& rect) {
1083 m_BaseClipBox = rect;
1084 }
1085
SetClip_PathFill(const CFX_PathData * pPathData,const CFX_Matrix * pMatrix,int fill_mode)1086 bool CGdiDeviceDriver::SetClip_PathFill(const CFX_PathData* pPathData,
1087 const CFX_Matrix* pMatrix,
1088 int fill_mode) {
1089 if (pPathData->GetPoints().size() == 5) {
1090 CFX_FloatRect rectf;
1091 if (pPathData->IsRect(pMatrix, &rectf)) {
1092 FX_RECT rect = rectf.GetOuterRect();
1093 // Can easily apply base clip to protect against wildly large rectangular
1094 // clips. crbug.com/1019026
1095 if (m_BaseClipBox.has_value())
1096 rect.Intersect(m_BaseClipBox.value());
1097 return IntersectClipRect(m_hDC, rect.left, rect.top, rect.right,
1098 rect.bottom) != ERROR;
1099 }
1100 }
1101 SetPathToDC(m_hDC, pPathData, pMatrix);
1102 SetPolyFillMode(m_hDC, fill_mode & 3);
1103 SelectClipPath(m_hDC, RGN_AND);
1104 return true;
1105 }
1106
SetClip_PathStroke(const CFX_PathData * pPathData,const CFX_Matrix * pMatrix,const CFX_GraphStateData * pGraphState)1107 bool CGdiDeviceDriver::SetClip_PathStroke(
1108 const CFX_PathData* pPathData,
1109 const CFX_Matrix* pMatrix,
1110 const CFX_GraphStateData* pGraphState) {
1111 HPEN hPen = CreateExtPen(pGraphState, pMatrix, 0xff000000);
1112 hPen = (HPEN)SelectObject(m_hDC, hPen);
1113 SetPathToDC(m_hDC, pPathData, pMatrix);
1114 WidenPath(m_hDC);
1115 SetPolyFillMode(m_hDC, WINDING);
1116 bool ret = !!SelectClipPath(m_hDC, RGN_AND);
1117 hPen = (HPEN)SelectObject(m_hDC, hPen);
1118 DeleteObject(hPen);
1119 return ret;
1120 }
1121
DrawCosmeticLine(const CFX_PointF & ptMoveTo,const CFX_PointF & ptLineTo,uint32_t color,BlendMode blend_type)1122 bool CGdiDeviceDriver::DrawCosmeticLine(const CFX_PointF& ptMoveTo,
1123 const CFX_PointF& ptLineTo,
1124 uint32_t color,
1125 BlendMode blend_type) {
1126 if (blend_type != BlendMode::kNormal)
1127 return false;
1128
1129 int alpha;
1130 FX_COLORREF colorref;
1131 std::tie(alpha, colorref) = ArgbToAlphaAndColorRef(color);
1132 if (alpha == 0)
1133 return true;
1134
1135 HPEN hPen = CreatePen(PS_SOLID, 1, colorref);
1136 hPen = (HPEN)SelectObject(m_hDC, hPen);
1137 MoveToEx(m_hDC, FXSYS_roundf(ptMoveTo.x), FXSYS_roundf(ptMoveTo.y), nullptr);
1138 LineTo(m_hDC, FXSYS_roundf(ptLineTo.x), FXSYS_roundf(ptLineTo.y));
1139 hPen = (HPEN)SelectObject(m_hDC, hPen);
1140 DeleteObject(hPen);
1141 return true;
1142 }
1143
CGdiDisplayDriver(HDC hDC)1144 CGdiDisplayDriver::CGdiDisplayDriver(HDC hDC)
1145 : CGdiDeviceDriver(hDC, DeviceType::kDisplay) {
1146 auto* pPlatform =
1147 static_cast<CWin32Platform*>(CFX_GEModule::Get()->GetPlatform());
1148 if (pPlatform->m_GdiplusExt.IsAvailable()) {
1149 m_RenderCaps |= FXRC_ALPHA_PATH | FXRC_ALPHA_IMAGE;
1150 }
1151 }
1152
1153 CGdiDisplayDriver::~CGdiDisplayDriver() = default;
1154
GetDeviceCaps(int caps_id) const1155 int CGdiDisplayDriver::GetDeviceCaps(int caps_id) const {
1156 if (caps_id == FXDC_HORZ_SIZE || caps_id == FXDC_VERT_SIZE)
1157 return 0;
1158 return CGdiDeviceDriver::GetDeviceCaps(caps_id);
1159 }
1160
GetDIBits(const RetainPtr<CFX_DIBitmap> & pBitmap,int left,int top)1161 bool CGdiDisplayDriver::GetDIBits(const RetainPtr<CFX_DIBitmap>& pBitmap,
1162 int left,
1163 int top) {
1164 bool ret = false;
1165 int width = pBitmap->GetWidth();
1166 int height = pBitmap->GetHeight();
1167 HBITMAP hbmp = CreateCompatibleBitmap(m_hDC, width, height);
1168 HDC hDCMemory = CreateCompatibleDC(m_hDC);
1169 HBITMAP holdbmp = (HBITMAP)SelectObject(hDCMemory, hbmp);
1170 BitBlt(hDCMemory, 0, 0, width, height, m_hDC, left, top, SRCCOPY);
1171 SelectObject(hDCMemory, holdbmp);
1172 BITMAPINFO bmi;
1173 memset(&bmi, 0, sizeof bmi);
1174 bmi.bmiHeader.biSize = sizeof bmi.bmiHeader;
1175 bmi.bmiHeader.biBitCount = pBitmap->GetBPP();
1176 bmi.bmiHeader.biHeight = -height;
1177 bmi.bmiHeader.biPlanes = 1;
1178 bmi.bmiHeader.biWidth = width;
1179 if (pBitmap->GetBPP() > 8 && !pBitmap->IsCmykImage()) {
1180 ret = ::GetDIBits(hDCMemory, hbmp, 0, height, pBitmap->GetBuffer(), &bmi,
1181 DIB_RGB_COLORS) == height;
1182 } else {
1183 auto bitmap = pdfium::MakeRetain<CFX_DIBitmap>();
1184 if (bitmap->Create(width, height, FXDIB_Rgb)) {
1185 bmi.bmiHeader.biBitCount = 24;
1186 ::GetDIBits(hDCMemory, hbmp, 0, height, bitmap->GetBuffer(), &bmi,
1187 DIB_RGB_COLORS);
1188 ret = pBitmap->TransferBitmap(0, 0, width, height, bitmap, 0, 0);
1189 } else {
1190 ret = false;
1191 }
1192 }
1193 if (pBitmap->HasAlpha() && ret)
1194 pBitmap->LoadChannel(FXDIB_Alpha, 0xff);
1195
1196 DeleteObject(hbmp);
1197 DeleteObject(hDCMemory);
1198 return ret;
1199 }
1200
SetDIBits(const RetainPtr<CFX_DIBBase> & pSource,uint32_t color,const FX_RECT & src_rect,int left,int top,BlendMode blend_type)1201 bool CGdiDisplayDriver::SetDIBits(const RetainPtr<CFX_DIBBase>& pSource,
1202 uint32_t color,
1203 const FX_RECT& src_rect,
1204 int left,
1205 int top,
1206 BlendMode blend_type) {
1207 ASSERT(blend_type == BlendMode::kNormal);
1208 if (pSource->IsAlphaMask()) {
1209 int width = pSource->GetWidth(), height = pSource->GetHeight();
1210 int alpha = FXARGB_A(color);
1211 if (pSource->GetBPP() != 1 || alpha != 255) {
1212 auto background = pdfium::MakeRetain<CFX_DIBitmap>();
1213 if (!background->Create(width, height, FXDIB_Rgb32) ||
1214 !GetDIBits(background, left, top) ||
1215 !background->CompositeMask(0, 0, width, height, pSource, color, 0, 0,
1216 BlendMode::kNormal, nullptr, false)) {
1217 return false;
1218 }
1219 FX_RECT alpha_src_rect(0, 0, width, height);
1220 return SetDIBits(background, 0, alpha_src_rect, left, top,
1221 BlendMode::kNormal);
1222 }
1223 FX_RECT clip_rect(left, top, left + src_rect.Width(),
1224 top + src_rect.Height());
1225 return StretchDIBits(pSource, color, left - src_rect.left,
1226 top - src_rect.top, width, height, &clip_rect,
1227 FXDIB_ResampleOptions(), BlendMode::kNormal);
1228 }
1229 int width = src_rect.Width();
1230 int height = src_rect.Height();
1231 if (pSource->HasAlpha()) {
1232 auto bitmap = pdfium::MakeRetain<CFX_DIBitmap>();
1233 if (!bitmap->Create(width, height, FXDIB_Rgb) ||
1234 !GetDIBits(bitmap, left, top) ||
1235 !bitmap->CompositeBitmap(0, 0, width, height, pSource, src_rect.left,
1236 src_rect.top, BlendMode::kNormal, nullptr,
1237 false)) {
1238 return false;
1239 }
1240 FX_RECT alpha_src_rect(0, 0, width, height);
1241 return SetDIBits(bitmap, 0, alpha_src_rect, left, top, BlendMode::kNormal);
1242 }
1243 CFX_DIBExtractor temp(pSource);
1244 RetainPtr<CFX_DIBitmap> pBitmap = temp.GetBitmap();
1245 if (!pBitmap)
1246 return false;
1247 return GDI_SetDIBits(pBitmap, src_rect, left, top);
1248 }
1249
UseFoxitStretchEngine(const RetainPtr<CFX_DIBBase> & pSource,uint32_t color,int dest_left,int dest_top,int dest_width,int dest_height,const FX_RECT * pClipRect,const FXDIB_ResampleOptions & options)1250 bool CGdiDisplayDriver::UseFoxitStretchEngine(
1251 const RetainPtr<CFX_DIBBase>& pSource,
1252 uint32_t color,
1253 int dest_left,
1254 int dest_top,
1255 int dest_width,
1256 int dest_height,
1257 const FX_RECT* pClipRect,
1258 const FXDIB_ResampleOptions& options) {
1259 FX_RECT bitmap_clip = *pClipRect;
1260 if (dest_width < 0)
1261 dest_left += dest_width;
1262
1263 if (dest_height < 0)
1264 dest_top += dest_height;
1265
1266 bitmap_clip.Offset(-dest_left, -dest_top);
1267 RetainPtr<CFX_DIBitmap> pStretched =
1268 pSource->StretchTo(dest_width, dest_height, options, &bitmap_clip);
1269 if (!pStretched)
1270 return true;
1271
1272 FX_RECT src_rect(0, 0, pStretched->GetWidth(), pStretched->GetHeight());
1273 return SetDIBits(pStretched, color, src_rect, pClipRect->left, pClipRect->top,
1274 BlendMode::kNormal);
1275 }
1276
StretchDIBits(const RetainPtr<CFX_DIBBase> & pSource,uint32_t color,int dest_left,int dest_top,int dest_width,int dest_height,const FX_RECT * pClipRect,const FXDIB_ResampleOptions & options,BlendMode blend_type)1277 bool CGdiDisplayDriver::StretchDIBits(const RetainPtr<CFX_DIBBase>& pSource,
1278 uint32_t color,
1279 int dest_left,
1280 int dest_top,
1281 int dest_width,
1282 int dest_height,
1283 const FX_RECT* pClipRect,
1284 const FXDIB_ResampleOptions& options,
1285 BlendMode blend_type) {
1286 ASSERT(pSource);
1287 ASSERT(pClipRect);
1288
1289 if (options.HasAnyOptions() || dest_width > 10000 || dest_width < -10000 ||
1290 dest_height > 10000 || dest_height < -10000) {
1291 return UseFoxitStretchEngine(pSource, color, dest_left, dest_top,
1292 dest_width, dest_height, pClipRect, options);
1293 }
1294 if (pSource->IsAlphaMask()) {
1295 FX_RECT image_rect;
1296 image_rect.left = dest_width > 0 ? dest_left : dest_left + dest_width;
1297 image_rect.right = dest_width > 0 ? dest_left + dest_width : dest_left;
1298 image_rect.top = dest_height > 0 ? dest_top : dest_top + dest_height;
1299 image_rect.bottom = dest_height > 0 ? dest_top + dest_height : dest_top;
1300 FX_RECT clip_rect = image_rect;
1301 clip_rect.Intersect(*pClipRect);
1302 clip_rect.Offset(-image_rect.left, -image_rect.top);
1303 int clip_width = clip_rect.Width(), clip_height = clip_rect.Height();
1304 RetainPtr<CFX_DIBitmap> pStretched(pSource->StretchTo(
1305 dest_width, dest_height, FXDIB_ResampleOptions(), &clip_rect));
1306 if (!pStretched)
1307 return true;
1308
1309 auto background = pdfium::MakeRetain<CFX_DIBitmap>();
1310 if (!background->Create(clip_width, clip_height, FXDIB_Rgb32) ||
1311 !GetDIBits(background, image_rect.left + clip_rect.left,
1312 image_rect.top + clip_rect.top) ||
1313 !background->CompositeMask(0, 0, clip_width, clip_height, pStretched,
1314 color, 0, 0, BlendMode::kNormal, nullptr,
1315 false)) {
1316 return false;
1317 }
1318
1319 FX_RECT src_rect(0, 0, clip_width, clip_height);
1320 return SetDIBits(background, 0, src_rect, image_rect.left + clip_rect.left,
1321 image_rect.top + clip_rect.top, BlendMode::kNormal);
1322 }
1323 if (pSource->HasAlpha()) {
1324 auto* pPlatform =
1325 static_cast<CWin32Platform*>(CFX_GEModule::Get()->GetPlatform());
1326 if (pPlatform->m_GdiplusExt.IsAvailable() && !pSource->IsCmykImage()) {
1327 CFX_DIBExtractor temp(pSource);
1328 RetainPtr<CFX_DIBitmap> pBitmap = temp.GetBitmap();
1329 if (!pBitmap)
1330 return false;
1331 return pPlatform->m_GdiplusExt.StretchDIBits(
1332 m_hDC, pBitmap, dest_left, dest_top, dest_width, dest_height,
1333 pClipRect, FXDIB_ResampleOptions());
1334 }
1335 return UseFoxitStretchEngine(pSource, color, dest_left, dest_top,
1336 dest_width, dest_height, pClipRect,
1337 FXDIB_ResampleOptions());
1338 }
1339 CFX_DIBExtractor temp(pSource);
1340 RetainPtr<CFX_DIBitmap> pBitmap = temp.GetBitmap();
1341 if (!pBitmap)
1342 return false;
1343 return GDI_StretchDIBits(pBitmap, dest_left, dest_top, dest_width,
1344 dest_height, FXDIB_ResampleOptions());
1345 }
1346
StartDIBits(const RetainPtr<CFX_DIBBase> & pBitmap,int bitmap_alpha,uint32_t color,const CFX_Matrix & matrix,const FXDIB_ResampleOptions & options,std::unique_ptr<CFX_ImageRenderer> * handle,BlendMode blend_type)1347 bool CGdiDisplayDriver::StartDIBits(const RetainPtr<CFX_DIBBase>& pBitmap,
1348 int bitmap_alpha,
1349 uint32_t color,
1350 const CFX_Matrix& matrix,
1351 const FXDIB_ResampleOptions& options,
1352 std::unique_ptr<CFX_ImageRenderer>* handle,
1353 BlendMode blend_type) {
1354 return false;
1355 }
1356
CFX_WindowsRenderDevice(HDC hDC,const EncoderIface * pEncoderIface)1357 CFX_WindowsRenderDevice::CFX_WindowsRenderDevice(
1358 HDC hDC,
1359 const EncoderIface* pEncoderIface) {
1360 SetDeviceDriver(pdfium::WrapUnique(CreateDriver(hDC, pEncoderIface)));
1361 }
1362
1363 CFX_WindowsRenderDevice::~CFX_WindowsRenderDevice() = default;
1364
1365 // static
CreateDriver(HDC hDC,const EncoderIface * pEncoderIface)1366 RenderDeviceDriverIface* CFX_WindowsRenderDevice::CreateDriver(
1367 HDC hDC,
1368 const EncoderIface* pEncoderIface) {
1369 int device_type = ::GetDeviceCaps(hDC, TECHNOLOGY);
1370 int obj_type = ::GetObjectType(hDC);
1371 bool use_printer = device_type == DT_RASPRINTER ||
1372 device_type == DT_PLOTTER ||
1373 device_type == DT_CHARSTREAM || obj_type == OBJ_ENHMETADC;
1374
1375 if (!use_printer)
1376 return new CGdiDisplayDriver(hDC);
1377
1378 if (g_pdfium_print_mode == WindowsPrintMode::kModeEmf)
1379 return new CGdiPrinterDriver(hDC);
1380
1381 if (g_pdfium_print_mode == WindowsPrintMode::kModeTextOnly)
1382 return new CTextOnlyPrinterDriver(hDC);
1383
1384 return new CPSPrinterDriver(hDC, g_pdfium_print_mode, false, pEncoderIface);
1385 }
1386