• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2020 The PDFium Authors
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 "core/fxge/win32/cgdi_device_driver.h"
8 
9 #include <math.h>
10 #include <windows.h>
11 
12 #include <algorithm>
13 #include <vector>
14 
15 #include "core/fxcrt/fx_string.h"
16 #include "core/fxge/agg/fx_agg_driver.h"
17 #include "core/fxge/cfx_defaultrenderdevice.h"
18 #include "core/fxge/cfx_fillrenderoptions.h"
19 #include "core/fxge/cfx_graphstatedata.h"
20 #include "core/fxge/cfx_path.h"
21 #include "core/fxge/dib/cfx_dibitmap.h"
22 #include "core/fxge/render_defines.h"
23 #include "core/fxge/win32/cwin32_platform.h"
24 #include "third_party/agg23/agg_clip_liang_barsky.h"
25 #include "third_party/base/check.h"
26 #include "third_party/base/check_op.h"
27 #include "third_party/base/notreached.h"
28 #include "third_party/base/numerics/safe_conversions.h"
29 
30 namespace {
31 
FillTypeToGdiFillType(CFX_FillRenderOptions::FillType fill_type)32 constexpr int FillTypeToGdiFillType(CFX_FillRenderOptions::FillType fill_type) {
33   return static_cast<int>(fill_type);
34 }
35 
36 static_assert(FillTypeToGdiFillType(
37                   CFX_FillRenderOptions::FillType::kEvenOdd) == ALTERNATE,
38               "CFX_FillRenderOptions::FillType::kEvenOdd value mismatch");
39 
40 static_assert(
41     FillTypeToGdiFillType(CFX_FillRenderOptions::FillType::kWinding) == WINDING,
42     "CFX_FillRenderOptions::FillType::kWinding value mismatch");
43 
CreateExtPen(const CFX_GraphStateData * pGraphState,const CFX_Matrix * pMatrix,uint32_t argb)44 HPEN CreateExtPen(const CFX_GraphStateData* pGraphState,
45                   const CFX_Matrix* pMatrix,
46                   uint32_t argb) {
47   DCHECK(pGraphState);
48 
49   float scale = 1.0f;
50   if (pMatrix) {
51     scale = fabs(pMatrix->a) > fabs(pMatrix->b) ? fabs(pMatrix->a)
52                                                 : fabs(pMatrix->b);
53   }
54   float width = std::max(scale * pGraphState->m_LineWidth, 1.0f);
55 
56   uint32_t PenStyle = PS_GEOMETRIC;
57   if (!pGraphState->m_DashArray.empty())
58     PenStyle |= PS_USERSTYLE;
59   else
60     PenStyle |= PS_SOLID;
61 
62   switch (pGraphState->m_LineCap) {
63     case CFX_GraphStateData::LineCap::kButt:
64       PenStyle |= PS_ENDCAP_FLAT;
65       break;
66     case CFX_GraphStateData::LineCap::kRound:
67       PenStyle |= PS_ENDCAP_ROUND;
68       break;
69     case CFX_GraphStateData::LineCap::kSquare:
70       PenStyle |= PS_ENDCAP_SQUARE;
71       break;
72   }
73   switch (pGraphState->m_LineJoin) {
74     case CFX_GraphStateData::LineJoin::kMiter:
75       PenStyle |= PS_JOIN_MITER;
76       break;
77     case CFX_GraphStateData::LineJoin::kRound:
78       PenStyle |= PS_JOIN_ROUND;
79       break;
80     case CFX_GraphStateData::LineJoin::kBevel:
81       PenStyle |= PS_JOIN_BEVEL;
82       break;
83   }
84 
85   FX_COLORREF colorref = ArgbToColorRef(argb);
86   LOGBRUSH lb;
87   lb.lbColor = colorref;
88   lb.lbStyle = BS_SOLID;
89   lb.lbHatch = 0;
90   std::vector<uint32_t> dashes;
91   if (!pGraphState->m_DashArray.empty()) {
92     dashes.resize(pGraphState->m_DashArray.size());
93     for (size_t i = 0; i < pGraphState->m_DashArray.size(); i++) {
94       dashes[i] = FXSYS_roundf(
95           pMatrix ? pMatrix->TransformDistance(pGraphState->m_DashArray[i])
96                   : pGraphState->m_DashArray[i]);
97       dashes[i] = std::max(dashes[i], 1U);
98     }
99   }
100   return ExtCreatePen(
101       PenStyle, (DWORD)ceil(width), &lb,
102       pdfium::base::checked_cast<DWORD>(pGraphState->m_DashArray.size()),
103       reinterpret_cast<const DWORD*>(dashes.data()));
104 }
105 
CreateBrush(uint32_t argb)106 HBRUSH CreateBrush(uint32_t argb) {
107   return CreateSolidBrush(ArgbToColorRef(argb));
108 }
109 
SetPathToDC(HDC hDC,const CFX_Path & path,const CFX_Matrix * pMatrix)110 void SetPathToDC(HDC hDC, const CFX_Path& path, const CFX_Matrix* pMatrix) {
111   BeginPath(hDC);
112 
113   pdfium::span<const CFX_Path::Point> points = path.GetPoints();
114   for (size_t i = 0; i < points.size(); ++i) {
115     CFX_PointF pos = points[i].m_Point;
116     if (pMatrix)
117       pos = pMatrix->Transform(pos);
118 
119     CFX_Point screen(FXSYS_roundf(pos.x), FXSYS_roundf(pos.y));
120     CFX_Path::Point::Type point_type = points[i].m_Type;
121     if (point_type == CFX_Path::Point::Type::kMove) {
122       MoveToEx(hDC, screen.x, screen.y, nullptr);
123     } else if (point_type == CFX_Path::Point::Type::kLine) {
124       if (points[i].m_Point == points[i - 1].m_Point)
125         screen.x++;
126 
127       LineTo(hDC, screen.x, screen.y);
128     } else if (point_type == CFX_Path::Point::Type::kBezier) {
129       POINT lppt[3];
130       lppt[0].x = screen.x;
131       lppt[0].y = screen.y;
132 
133       pos = points[i + 1].m_Point;
134       if (pMatrix)
135         pos = pMatrix->Transform(pos);
136 
137       lppt[1].x = FXSYS_roundf(pos.x);
138       lppt[1].y = FXSYS_roundf(pos.y);
139 
140       pos = points[i + 2].m_Point;
141       if (pMatrix)
142         pos = pMatrix->Transform(pos);
143 
144       lppt[2].x = FXSYS_roundf(pos.x);
145       lppt[2].y = FXSYS_roundf(pos.y);
146       PolyBezierTo(hDC, lppt, 3);
147       i += 2;
148     }
149     if (points[i].m_CloseFigure)
150       CloseFigure(hDC);
151   }
152   EndPath(hDC);
153 }
154 
GetBitmapInfo(const RetainPtr<CFX_DIBitmap> & pBitmap)155 ByteString GetBitmapInfo(const RetainPtr<CFX_DIBitmap>& pBitmap) {
156   int len = sizeof(BITMAPINFOHEADER);
157   if (pBitmap->GetBPP() == 1 || pBitmap->GetBPP() == 8)
158     len += sizeof(DWORD) * (int)(1 << pBitmap->GetBPP());
159 
160   ByteString result;
161   {
162     // Span's lifetime must end before ReleaseBuffer() below.
163     pdfium::span<char> cspan = result.GetBuffer(len);
164     BITMAPINFOHEADER* pbmih = reinterpret_cast<BITMAPINFOHEADER*>(cspan.data());
165     memset(pbmih, 0, sizeof(BITMAPINFOHEADER));
166     pbmih->biSize = sizeof(BITMAPINFOHEADER);
167     pbmih->biBitCount = pBitmap->GetBPP();
168     pbmih->biCompression = BI_RGB;
169     pbmih->biHeight = -(int)pBitmap->GetHeight();
170     pbmih->biPlanes = 1;
171     pbmih->biWidth = pBitmap->GetWidth();
172     if (pBitmap->GetBPP() == 8) {
173       uint32_t* pPalette = (uint32_t*)(pbmih + 1);
174       if (pBitmap->HasPalette()) {
175         pdfium::span<const uint32_t> palette = pBitmap->GetPaletteSpan();
176         for (int i = 0; i < 256; i++)
177           pPalette[i] = palette[i];
178       } else {
179         for (int i = 0; i < 256; i++)
180           pPalette[i] = ArgbEncode(0, i, i, i);
181       }
182     }
183     if (pBitmap->GetBPP() == 1) {
184       uint32_t* pPalette = (uint32_t*)(pbmih + 1);
185       if (pBitmap->HasPalette()) {
186         pPalette[0] = pBitmap->GetPaletteSpan()[0];
187         pPalette[1] = pBitmap->GetPaletteSpan()[1];
188       } else {
189         pPalette[0] = 0;
190         pPalette[1] = 0xffffff;
191       }
192     }
193   }
194   result.ReleaseBuffer(len);
195   return result;
196 }
197 
198 #if defined(_SKIA_SUPPORT_)
199 // TODO(caryclark)  This antigrain function is duplicated here to permit
200 // removing the last remaining dependency. Eventually, this will be elminiated
201 // altogether and replace by Skia code.
202 
203 struct rect_base {
204   float x1;
205   float y1;
206   float x2;
207   float y2;
208 };
209 
clip_liang_barsky(float x1,float y1,float x2,float y2,const rect_base & clip_box,float * x,float * y)210 unsigned clip_liang_barsky(float x1,
211                            float y1,
212                            float x2,
213                            float y2,
214                            const rect_base& clip_box,
215                            float* x,
216                            float* y) {
217   const float nearzero = 1e-30f;
218   float deltax = x2 - x1;
219   float deltay = y2 - y1;
220   unsigned np = 0;
221   if (deltax == 0)
222     deltax = (x1 > clip_box.x1) ? -nearzero : nearzero;
223   float xin;
224   float xout;
225   if (deltax > 0) {
226     xin = clip_box.x1;
227     xout = clip_box.x2;
228   } else {
229     xin = clip_box.x2;
230     xout = clip_box.x1;
231   }
232   float tinx = (xin - x1) / deltax;
233   if (deltay == 0)
234     deltay = (y1 > clip_box.y1) ? -nearzero : nearzero;
235   float yin;
236   float yout;
237   if (deltay > 0) {
238     yin = clip_box.y1;
239     yout = clip_box.y2;
240   } else {
241     yin = clip_box.y2;
242     yout = clip_box.y1;
243   }
244   float tiny = (yin - y1) / deltay;
245   float tin1;
246   float tin2;
247   if (tinx < tiny) {
248     tin1 = tinx;
249     tin2 = tiny;
250   } else {
251     tin1 = tiny;
252     tin2 = tinx;
253   }
254   if (tin1 <= 1.0f) {
255     if (0 < tin1) {
256       *x++ = xin;
257       *y++ = yin;
258       ++np;
259     }
260     if (tin2 <= 1.0f) {
261       float toutx = (xout - x1) / deltax;
262       float touty = (yout - y1) / deltay;
263       float tout1 = (toutx < touty) ? toutx : touty;
264       if (tin2 > 0 || tout1 > 0) {
265         if (tin2 <= tout1) {
266           if (tin2 > 0) {
267             if (tinx > tiny) {
268               *x++ = xin;
269               *y++ = y1 + (deltay * tinx);
270             } else {
271               *x++ = x1 + (deltax * tiny);
272               *y++ = yin;
273             }
274             ++np;
275           }
276           if (tout1 < 1.0f) {
277             if (toutx < touty) {
278               *x++ = xout;
279               *y++ = y1 + (deltay * toutx);
280             } else {
281               *x++ = x1 + (deltax * touty);
282               *y++ = yout;
283             }
284           } else {
285             *x++ = x2;
286             *y++ = y2;
287           }
288           ++np;
289         } else {
290           if (tinx > tiny) {
291             *x++ = xin;
292             *y++ = yout;
293           } else {
294             *x++ = xout;
295             *y++ = yin;
296           }
297           ++np;
298         }
299       }
300     }
301   }
302   return np;
303 }
304 #endif  //  defined(_SKIA_SUPPORT_)
305 
LineClip(float w,float h,float x1,float y1,float x2,float y2,float * x,float * y)306 unsigned LineClip(float w,
307                   float h,
308                   float x1,
309                   float y1,
310                   float x2,
311                   float y2,
312                   float* x,
313                   float* y) {
314 #if defined(_SKIA_SUPPORT_)
315   if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer()) {
316     // TODO(caryclark) temporary replacement of antigrain in line function to
317     // permit removing antigrain altogether
318     rect_base rect = {0.0f, 0.0f, w, h};
319     return clip_liang_barsky(x1, y1, x2, y2, rect, x, y);
320   }
321 #endif
322   pdfium::agg::rect_base<float> rect(0.0f, 0.0f, w, h);
323   return pdfium::agg::clip_liang_barsky<float>(x1, y1, x2, y2, rect, x, y);
324 }
325 
326 }  // namespace
327 
CGdiDeviceDriver(HDC hDC,DeviceType device_type)328 CGdiDeviceDriver::CGdiDeviceDriver(HDC hDC, DeviceType device_type)
329     : m_hDC(hDC), m_DeviceType(device_type) {
330   SetStretchBltMode(m_hDC, HALFTONE);
331   DWORD obj_type = GetObjectType(m_hDC);
332   m_bMetafileDCType = obj_type == OBJ_ENHMETADC || obj_type == OBJ_ENHMETAFILE;
333   if (obj_type == OBJ_MEMDC) {
334     HBITMAP hBitmap = CreateBitmap(1, 1, 1, 1, nullptr);
335     hBitmap = (HBITMAP)SelectObject(m_hDC, hBitmap);
336     BITMAP bitmap;
337     GetObject(hBitmap, sizeof bitmap, &bitmap);
338     m_nBitsPerPixel = bitmap.bmBitsPixel;
339     m_Width = bitmap.bmWidth;
340     m_Height = abs(bitmap.bmHeight);
341     hBitmap = (HBITMAP)SelectObject(m_hDC, hBitmap);
342     DeleteObject(hBitmap);
343   } else {
344     m_nBitsPerPixel = ::GetDeviceCaps(m_hDC, BITSPIXEL);
345     m_Width = ::GetDeviceCaps(m_hDC, HORZRES);
346     m_Height = ::GetDeviceCaps(m_hDC, VERTRES);
347   }
348   if (m_DeviceType != DeviceType::kDisplay) {
349     m_RenderCaps = FXRC_BIT_MASK;
350   } else {
351     m_RenderCaps = FXRC_GET_BITS | FXRC_BIT_MASK;
352   }
353 }
354 
355 CGdiDeviceDriver::~CGdiDeviceDriver() = default;
356 
GetDeviceType() const357 DeviceType CGdiDeviceDriver::GetDeviceType() const {
358   return m_DeviceType;
359 }
360 
GetDeviceCaps(int caps_id) const361 int CGdiDeviceDriver::GetDeviceCaps(int caps_id) const {
362   switch (caps_id) {
363     case FXDC_PIXEL_WIDTH:
364       return m_Width;
365     case FXDC_PIXEL_HEIGHT:
366       return m_Height;
367     case FXDC_BITS_PIXEL:
368       return m_nBitsPerPixel;
369     case FXDC_RENDER_CAPS:
370       return m_RenderCaps;
371     default:
372       NOTREACHED();
373       return 0;
374   }
375 }
376 
SaveState()377 void CGdiDeviceDriver::SaveState() {
378   SaveDC(m_hDC);
379 }
380 
RestoreState(bool bKeepSaved)381 void CGdiDeviceDriver::RestoreState(bool bKeepSaved) {
382   RestoreDC(m_hDC, -1);
383   if (bKeepSaved)
384     SaveDC(m_hDC);
385 }
386 
GDI_SetDIBits(const RetainPtr<CFX_DIBitmap> & pBitmap1,const FX_RECT & src_rect,int left,int top)387 bool CGdiDeviceDriver::GDI_SetDIBits(const RetainPtr<CFX_DIBitmap>& pBitmap1,
388                                      const FX_RECT& src_rect,
389                                      int left,
390                                      int top) {
391   if (m_DeviceType == DeviceType::kPrinter) {
392     RetainPtr<CFX_DIBitmap> pBitmap = pBitmap1->FlipImage(false, true);
393     if (!pBitmap)
394       return false;
395 
396     LPBYTE pBuffer = pBitmap->GetBuffer().data();
397     ByteString info = GetBitmapInfo(pBitmap);
398     ((BITMAPINFOHEADER*)info.c_str())->biHeight *= -1;
399     FX_RECT dst_rect(0, 0, src_rect.Width(), src_rect.Height());
400     dst_rect.Intersect(0, 0, pBitmap->GetWidth(), pBitmap->GetHeight());
401     int dst_width = dst_rect.Width();
402     int dst_height = dst_rect.Height();
403     ::StretchDIBits(m_hDC, left, top, dst_width, dst_height, 0, 0, dst_width,
404                     dst_height, pBuffer, (BITMAPINFO*)info.c_str(),
405                     DIB_RGB_COLORS, SRCCOPY);
406     return true;
407   }
408 
409   RetainPtr<CFX_DIBitmap> pBitmap = pBitmap1;
410   LPBYTE pBuffer = pBitmap->GetBuffer().data();
411   ByteString info = GetBitmapInfo(pBitmap);
412   ::SetDIBitsToDevice(m_hDC, left, top, src_rect.Width(), src_rect.Height(),
413                       src_rect.left, pBitmap->GetHeight() - src_rect.bottom, 0,
414                       pBitmap->GetHeight(), pBuffer, (BITMAPINFO*)info.c_str(),
415                       DIB_RGB_COLORS);
416   return true;
417 }
418 
GDI_StretchDIBits(const RetainPtr<CFX_DIBitmap> & pBitmap1,int dest_left,int dest_top,int dest_width,int dest_height,const FXDIB_ResampleOptions & options)419 bool CGdiDeviceDriver::GDI_StretchDIBits(
420     const RetainPtr<CFX_DIBitmap>& pBitmap1,
421     int dest_left,
422     int dest_top,
423     int dest_width,
424     int dest_height,
425     const FXDIB_ResampleOptions& options) {
426   RetainPtr<CFX_DIBitmap> pBitmap = pBitmap1;
427   if (!pBitmap || dest_width == 0 || dest_height == 0)
428     return false;
429 
430   ByteString info = GetBitmapInfo(pBitmap);
431   if ((int64_t)abs(dest_width) * abs(dest_height) <
432           (int64_t)pBitmap1->GetWidth() * pBitmap1->GetHeight() * 4 ||
433       options.bInterpolateBilinear) {
434     SetStretchBltMode(m_hDC, HALFTONE);
435   } else {
436     SetStretchBltMode(m_hDC, COLORONCOLOR);
437   }
438   RetainPtr<CFX_DIBitmap> pToStrechBitmap = pBitmap;
439   if (m_DeviceType == DeviceType::kPrinter &&
440       ((int64_t)pBitmap->GetWidth() * pBitmap->GetHeight() >
441        (int64_t)abs(dest_width) * abs(dest_height))) {
442     pToStrechBitmap = pBitmap->StretchTo(dest_width, dest_height,
443                                          FXDIB_ResampleOptions(), nullptr);
444   }
445   ByteString toStrechBitmapInfo = GetBitmapInfo(pToStrechBitmap);
446   ::StretchDIBits(m_hDC, dest_left, dest_top, dest_width, dest_height, 0, 0,
447                   pToStrechBitmap->GetWidth(), pToStrechBitmap->GetHeight(),
448                   pToStrechBitmap->GetBuffer().data(),
449                   (BITMAPINFO*)toStrechBitmapInfo.c_str(), DIB_RGB_COLORS,
450                   SRCCOPY);
451   return true;
452 }
453 
GDI_StretchBitMask(const RetainPtr<CFX_DIBitmap> & pBitmap1,int dest_left,int dest_top,int dest_width,int dest_height,uint32_t bitmap_color)454 bool CGdiDeviceDriver::GDI_StretchBitMask(
455     const RetainPtr<CFX_DIBitmap>& pBitmap1,
456     int dest_left,
457     int dest_top,
458     int dest_width,
459     int dest_height,
460     uint32_t bitmap_color) {
461   RetainPtr<CFX_DIBitmap> pBitmap = pBitmap1;
462   if (!pBitmap || dest_width == 0 || dest_height == 0)
463     return false;
464 
465   int width = pBitmap->GetWidth(), height = pBitmap->GetHeight();
466   struct {
467     BITMAPINFOHEADER bmiHeader;
468     uint32_t bmiColors[2];
469   } bmi;
470   memset(&bmi.bmiHeader, 0, sizeof(BITMAPINFOHEADER));
471   bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
472   bmi.bmiHeader.biBitCount = 1;
473   bmi.bmiHeader.biCompression = BI_RGB;
474   bmi.bmiHeader.biHeight = -height;
475   bmi.bmiHeader.biPlanes = 1;
476   bmi.bmiHeader.biWidth = width;
477   if (m_nBitsPerPixel != 1) {
478     SetStretchBltMode(m_hDC, HALFTONE);
479   }
480   bmi.bmiColors[0] = 0xffffff;
481   bmi.bmiColors[1] = 0;
482 
483   HBRUSH hPattern = CreateBrush(bitmap_color);
484   HBRUSH hOld = (HBRUSH)SelectObject(m_hDC, hPattern);
485 
486   // In PDF, when image mask is 1, use device bitmap; when mask is 0, use brush
487   // bitmap.
488   // A complete list of the boolen operations is as follows:
489 
490   /* P(bitmap_color)    S(ImageMask)    D(DeviceBitmap)    Result
491    *        0                 0                0              0
492    *        0                 0                1              0
493    *        0                 1                0              0
494    *        0                 1                1              1
495    *        1                 0                0              1
496    *        1                 0                1              1
497    *        1                 1                0              0
498    *        1                 1                1              1
499    */
500   // The boolen codes is B8. Based on
501   // http://msdn.microsoft.com/en-us/library/aa932106.aspx, the ROP3 code is
502   // 0xB8074A
503 
504   ::StretchDIBits(m_hDC, dest_left, dest_top, dest_width, dest_height, 0, 0,
505                   width, height, pBitmap->GetBuffer().data(), (BITMAPINFO*)&bmi,
506                   DIB_RGB_COLORS, 0xB8074A);
507 
508   SelectObject(m_hDC, hOld);
509   DeleteObject(hPattern);
510 
511   return true;
512 }
513 
GetClipBox(FX_RECT * pRect)514 bool CGdiDeviceDriver::GetClipBox(FX_RECT* pRect) {
515   return !!(::GetClipBox(m_hDC, (RECT*)pRect));
516 }
517 
MultiplyAlpha(float alpha)518 bool CGdiDeviceDriver::MultiplyAlpha(float alpha) {
519   // Not implemented. All callers are using `CFX_DIBitmap`-backed raster devices
520   // anyway.
521   NOTREACHED();
522   return false;
523 }
524 
MultiplyAlpha(const RetainPtr<CFX_DIBBase> & mask)525 bool CGdiDeviceDriver::MultiplyAlpha(const RetainPtr<CFX_DIBBase>& mask) {
526   // Not implemented. All callers are using `CFX_DIBitmap`-backed raster devices
527   // anyway.
528   NOTREACHED();
529   return false;
530 }
531 
DrawLine(float x1,float y1,float x2,float y2)532 void CGdiDeviceDriver::DrawLine(float x1, float y1, float x2, float y2) {
533   if (!m_bMetafileDCType) {  // EMF drawing is not bound to the DC.
534     int startOutOfBoundsFlag = (x1 < 0) | ((x1 > m_Width) << 1) |
535                                ((y1 < 0) << 2) | ((y1 > m_Height) << 3);
536     int endOutOfBoundsFlag = (x2 < 0) | ((x2 > m_Width) << 1) |
537                              ((y2 < 0) << 2) | ((y2 > m_Height) << 3);
538     if (startOutOfBoundsFlag & endOutOfBoundsFlag)
539       return;
540 
541     if (startOutOfBoundsFlag || endOutOfBoundsFlag) {
542       float x[2];
543       float y[2];
544       unsigned np = LineClip(m_Width, m_Height, x1, y1, x2, y2, x, y);
545       if (np == 0)
546         return;
547 
548       if (np == 1) {
549         x2 = x[0];
550         y2 = y[0];
551       } else {
552         DCHECK_EQ(np, 2);
553         x1 = x[0];
554         y1 = y[0];
555         x2 = x[1];
556         y2 = y[1];
557       }
558     }
559   }
560 
561   MoveToEx(m_hDC, FXSYS_roundf(x1), FXSYS_roundf(y1), nullptr);
562   LineTo(m_hDC, FXSYS_roundf(x2), FXSYS_roundf(y2));
563 }
564 
DrawPath(const CFX_Path & path,const CFX_Matrix * pMatrix,const CFX_GraphStateData * pGraphState,uint32_t fill_color,uint32_t stroke_color,const CFX_FillRenderOptions & fill_options,BlendMode blend_type)565 bool CGdiDeviceDriver::DrawPath(const CFX_Path& path,
566                                 const CFX_Matrix* pMatrix,
567                                 const CFX_GraphStateData* pGraphState,
568                                 uint32_t fill_color,
569                                 uint32_t stroke_color,
570                                 const CFX_FillRenderOptions& fill_options,
571                                 BlendMode blend_type) {
572   if (blend_type != BlendMode::kNormal)
573     return false;
574 
575   auto* pPlatform =
576       static_cast<CWin32Platform*>(CFX_GEModule::Get()->GetPlatform());
577   if (!(pGraphState || stroke_color == 0) &&
578       !pPlatform->m_GdiplusExt.IsAvailable()) {
579     CFX_FloatRect bbox_f = path.GetBoundingBox();
580     if (pMatrix)
581       bbox_f = pMatrix->TransformRect(bbox_f);
582 
583     FX_RECT bbox = bbox_f.GetInnerRect();
584     if (bbox.Width() <= 0) {
585       return DrawCosmeticLine(CFX_PointF(bbox.left, bbox.top),
586                               CFX_PointF(bbox.left, bbox.bottom + 1),
587                               fill_color, BlendMode::kNormal);
588     }
589     if (bbox.Height() <= 0) {
590       return DrawCosmeticLine(CFX_PointF(bbox.left, bbox.top),
591                               CFX_PointF(bbox.right + 1, bbox.top), fill_color,
592                               BlendMode::kNormal);
593     }
594   }
595   int fill_alpha = FXARGB_A(fill_color);
596   int stroke_alpha = FXARGB_A(stroke_color);
597   bool bDrawAlpha = (fill_alpha > 0 && fill_alpha < 255) ||
598                     (stroke_alpha > 0 && stroke_alpha < 255 && pGraphState);
599   if (!pPlatform->m_GdiplusExt.IsAvailable() && bDrawAlpha)
600     return false;
601 
602   if (pPlatform->m_GdiplusExt.IsAvailable()) {
603     if (bDrawAlpha ||
604         ((m_DeviceType != DeviceType::kPrinter && !fill_options.full_cover) ||
605          (pGraphState && !pGraphState->m_DashArray.empty()))) {
606       if (!((!pMatrix || !pMatrix->WillScale()) && pGraphState &&
607             pGraphState->m_LineWidth == 1.0f && path.IsRect())) {
608         if (pPlatform->m_GdiplusExt.DrawPath(m_hDC, path, pMatrix, pGraphState,
609                                              fill_color, stroke_color,
610                                              fill_options)) {
611           return true;
612         }
613       }
614     }
615   }
616   const bool fill =
617       fill_options.fill_type != CFX_FillRenderOptions::FillType::kNoFill;
618   HPEN hPen = nullptr;
619   HBRUSH hBrush = nullptr;
620   if (pGraphState && stroke_alpha) {
621     SetMiterLimit(m_hDC, pGraphState->m_MiterLimit, nullptr);
622     hPen = CreateExtPen(pGraphState, pMatrix, stroke_color);
623     hPen = (HPEN)SelectObject(m_hDC, hPen);
624   }
625   if (fill && fill_alpha) {
626     SetPolyFillMode(m_hDC, FillTypeToGdiFillType(fill_options.fill_type));
627     hBrush = CreateBrush(fill_color);
628     hBrush = (HBRUSH)SelectObject(m_hDC, hBrush);
629   }
630   if (path.GetPoints().size() == 2 && pGraphState &&
631       !pGraphState->m_DashArray.empty()) {
632     CFX_PointF pos1 = path.GetPoint(0);
633     CFX_PointF pos2 = path.GetPoint(1);
634     if (pMatrix) {
635       pos1 = pMatrix->Transform(pos1);
636       pos2 = pMatrix->Transform(pos2);
637     }
638     DrawLine(pos1.x, pos1.y, pos2.x, pos2.y);
639   } else {
640     SetPathToDC(m_hDC, path, pMatrix);
641     if (pGraphState && stroke_alpha) {
642       if (fill && fill_alpha) {
643         if (fill_options.text_mode) {
644           StrokeAndFillPath(m_hDC);
645         } else {
646           FillPath(m_hDC);
647           SetPathToDC(m_hDC, path, pMatrix);
648           StrokePath(m_hDC);
649         }
650       } else {
651         StrokePath(m_hDC);
652       }
653     } else if (fill && fill_alpha) {
654       FillPath(m_hDC);
655     }
656   }
657   if (hPen) {
658     hPen = (HPEN)SelectObject(m_hDC, hPen);
659     DeleteObject(hPen);
660   }
661   if (hBrush) {
662     hBrush = (HBRUSH)SelectObject(m_hDC, hBrush);
663     DeleteObject(hBrush);
664   }
665   return true;
666 }
667 
FillRectWithBlend(const FX_RECT & rect,uint32_t fill_color,BlendMode blend_type)668 bool CGdiDeviceDriver::FillRectWithBlend(const FX_RECT& rect,
669                                          uint32_t fill_color,
670                                          BlendMode blend_type) {
671   if (blend_type != BlendMode::kNormal)
672     return false;
673 
674   int alpha;
675   FX_COLORREF colorref;
676   std::tie(alpha, colorref) = ArgbToAlphaAndColorRef(fill_color);
677   if (alpha == 0)
678     return true;
679 
680   if (alpha < 255)
681     return false;
682 
683   HBRUSH hBrush = CreateSolidBrush(colorref);
684   const RECT* pRect = reinterpret_cast<const RECT*>(&rect);
685   ::FillRect(m_hDC, pRect, hBrush);
686   DeleteObject(hBrush);
687   return true;
688 }
689 
SetBaseClip(const FX_RECT & rect)690 void CGdiDeviceDriver::SetBaseClip(const FX_RECT& rect) {
691   m_BaseClipBox = rect;
692 }
693 
SetClip_PathFill(const CFX_Path & path,const CFX_Matrix * pMatrix,const CFX_FillRenderOptions & fill_options)694 bool CGdiDeviceDriver::SetClip_PathFill(
695     const CFX_Path& path,
696     const CFX_Matrix* pMatrix,
697     const CFX_FillRenderOptions& fill_options) {
698   absl::optional<CFX_FloatRect> maybe_rectf = path.GetRect(pMatrix);
699   if (maybe_rectf.has_value()) {
700     FX_RECT rect = maybe_rectf.value().GetOuterRect();
701     // Can easily apply base clip to protect against wildly large rectangular
702     // clips. crbug.com/1019026
703     if (m_BaseClipBox.has_value())
704       rect.Intersect(m_BaseClipBox.value());
705     return IntersectClipRect(m_hDC, rect.left, rect.top, rect.right,
706                              rect.bottom) != ERROR;
707   }
708   SetPathToDC(m_hDC, path, pMatrix);
709   SetPolyFillMode(m_hDC, FillTypeToGdiFillType(fill_options.fill_type));
710   SelectClipPath(m_hDC, RGN_AND);
711   return true;
712 }
713 
SetClip_PathStroke(const CFX_Path & path,const CFX_Matrix * pMatrix,const CFX_GraphStateData * pGraphState)714 bool CGdiDeviceDriver::SetClip_PathStroke(
715     const CFX_Path& path,
716     const CFX_Matrix* pMatrix,
717     const CFX_GraphStateData* pGraphState) {
718   HPEN hPen = CreateExtPen(pGraphState, pMatrix, 0xff000000);
719   hPen = (HPEN)SelectObject(m_hDC, hPen);
720   SetPathToDC(m_hDC, path, pMatrix);
721   WidenPath(m_hDC);
722   SetPolyFillMode(m_hDC, WINDING);
723   bool ret = !!SelectClipPath(m_hDC, RGN_AND);
724   hPen = (HPEN)SelectObject(m_hDC, hPen);
725   DeleteObject(hPen);
726   return ret;
727 }
728 
DrawCosmeticLine(const CFX_PointF & ptMoveTo,const CFX_PointF & ptLineTo,uint32_t color,BlendMode blend_type)729 bool CGdiDeviceDriver::DrawCosmeticLine(const CFX_PointF& ptMoveTo,
730                                         const CFX_PointF& ptLineTo,
731                                         uint32_t color,
732                                         BlendMode blend_type) {
733   if (blend_type != BlendMode::kNormal)
734     return false;
735 
736   int alpha;
737   FX_COLORREF colorref;
738   std::tie(alpha, colorref) = ArgbToAlphaAndColorRef(color);
739   if (alpha == 0)
740     return true;
741 
742   HPEN hPen = CreatePen(PS_SOLID, 1, colorref);
743   hPen = (HPEN)SelectObject(m_hDC, hPen);
744   MoveToEx(m_hDC, FXSYS_roundf(ptMoveTo.x), FXSYS_roundf(ptMoveTo.y), nullptr);
745   LineTo(m_hDC, FXSYS_roundf(ptLineTo.x), FXSYS_roundf(ptLineTo.y));
746   hPen = (HPEN)SelectObject(m_hDC, hPen);
747   DeleteObject(hPen);
748   return true;
749 }
750