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