• 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_display_driver.h"
8 
9 #include "core/fxcrt/fx_coordinates.h"
10 #include "core/fxcrt/fx_system.h"
11 #include "core/fxge/dib/cfx_dibextractor.h"
12 #include "core/fxge/dib/cfx_dibitmap.h"
13 #include "core/fxge/render_defines.h"
14 #include "core/fxge/win32/cwin32_platform.h"
15 #include "third_party/base/check.h"
16 #include "third_party/base/check_op.h"
17 
CGdiDisplayDriver(HDC hDC)18 CGdiDisplayDriver::CGdiDisplayDriver(HDC hDC)
19     : CGdiDeviceDriver(hDC, DeviceType::kDisplay) {
20   auto* pPlatform =
21       static_cast<CWin32Platform*>(CFX_GEModule::Get()->GetPlatform());
22   if (pPlatform->m_GdiplusExt.IsAvailable()) {
23     m_RenderCaps |= FXRC_ALPHA_PATH | FXRC_ALPHA_IMAGE;
24   }
25 }
26 
27 CGdiDisplayDriver::~CGdiDisplayDriver() = default;
28 
GetDeviceCaps(int caps_id) const29 int CGdiDisplayDriver::GetDeviceCaps(int caps_id) const {
30   if (caps_id == FXDC_HORZ_SIZE || caps_id == FXDC_VERT_SIZE)
31     return 0;
32   return CGdiDeviceDriver::GetDeviceCaps(caps_id);
33 }
34 
GetDIBits(const RetainPtr<CFX_DIBitmap> & pBitmap,int left,int top)35 bool CGdiDisplayDriver::GetDIBits(const RetainPtr<CFX_DIBitmap>& pBitmap,
36                                   int left,
37                                   int top) {
38   bool ret = false;
39   int width = pBitmap->GetWidth();
40   int height = pBitmap->GetHeight();
41   HBITMAP hbmp = CreateCompatibleBitmap(m_hDC, width, height);
42   HDC hDCMemory = CreateCompatibleDC(m_hDC);
43   HBITMAP holdbmp = (HBITMAP)SelectObject(hDCMemory, hbmp);
44   BitBlt(hDCMemory, 0, 0, width, height, m_hDC, left, top, SRCCOPY);
45   SelectObject(hDCMemory, holdbmp);
46   BITMAPINFO bmi;
47   memset(&bmi, 0, sizeof bmi);
48   bmi.bmiHeader.biSize = sizeof bmi.bmiHeader;
49   bmi.bmiHeader.biBitCount = pBitmap->GetBPP();
50   bmi.bmiHeader.biHeight = -height;
51   bmi.bmiHeader.biPlanes = 1;
52   bmi.bmiHeader.biWidth = width;
53   if (pBitmap->GetBPP() > 8) {
54     ret = ::GetDIBits(hDCMemory, hbmp, 0, height, pBitmap->GetBuffer().data(),
55                       &bmi, DIB_RGB_COLORS) == height;
56   } else {
57     auto bitmap = pdfium::MakeRetain<CFX_DIBitmap>();
58     if (bitmap->Create(width, height, FXDIB_Format::kRgb)) {
59       bmi.bmiHeader.biBitCount = 24;
60       ::GetDIBits(hDCMemory, hbmp, 0, height, bitmap->GetBuffer().data(), &bmi,
61                   DIB_RGB_COLORS);
62       ret = pBitmap->TransferBitmap(0, 0, width, height, bitmap, 0, 0);
63     } else {
64       ret = false;
65     }
66   }
67   if (ret && pBitmap->IsAlphaFormat())
68     pBitmap->SetUniformOpaqueAlpha();
69 
70   DeleteObject(hbmp);
71   DeleteObject(hDCMemory);
72   return ret;
73 }
74 
SetDIBits(const RetainPtr<CFX_DIBBase> & pSource,uint32_t color,const FX_RECT & src_rect,int left,int top,BlendMode blend_type)75 bool CGdiDisplayDriver::SetDIBits(const RetainPtr<CFX_DIBBase>& pSource,
76                                   uint32_t color,
77                                   const FX_RECT& src_rect,
78                                   int left,
79                                   int top,
80                                   BlendMode blend_type) {
81   DCHECK_EQ(blend_type, BlendMode::kNormal);
82   if (pSource->IsMaskFormat()) {
83     int width = pSource->GetWidth(), height = pSource->GetHeight();
84     int alpha = FXARGB_A(color);
85     if (pSource->GetBPP() != 1 || alpha != 255) {
86       auto background = pdfium::MakeRetain<CFX_DIBitmap>();
87       if (!background->Create(width, height, FXDIB_Format::kRgb32) ||
88           !GetDIBits(background, left, top) ||
89           !background->CompositeMask(0, 0, width, height, pSource, color, 0, 0,
90                                      BlendMode::kNormal, nullptr, false)) {
91         return false;
92       }
93       FX_RECT alpha_src_rect(0, 0, width, height);
94       return SetDIBits(background, 0, alpha_src_rect, left, top,
95                        BlendMode::kNormal);
96     }
97     FX_RECT clip_rect(left, top, left + src_rect.Width(),
98                       top + src_rect.Height());
99     return StretchDIBits(pSource, color, left - src_rect.left,
100                          top - src_rect.top, width, height, &clip_rect,
101                          FXDIB_ResampleOptions(), BlendMode::kNormal);
102   }
103   int width = src_rect.Width();
104   int height = src_rect.Height();
105   if (pSource->IsAlphaFormat()) {
106     auto bitmap = pdfium::MakeRetain<CFX_DIBitmap>();
107     if (!bitmap->Create(width, height, FXDIB_Format::kRgb) ||
108         !GetDIBits(bitmap, left, top) ||
109         !bitmap->CompositeBitmap(0, 0, width, height, pSource, src_rect.left,
110                                  src_rect.top, BlendMode::kNormal, nullptr,
111                                  false)) {
112       return false;
113     }
114     FX_RECT alpha_src_rect(0, 0, width, height);
115     return SetDIBits(bitmap, 0, alpha_src_rect, left, top, BlendMode::kNormal);
116   }
117   CFX_DIBExtractor temp(pSource);
118   RetainPtr<CFX_DIBitmap> pBitmap = temp.GetBitmap();
119   if (!pBitmap)
120     return false;
121   return GDI_SetDIBits(pBitmap, src_rect, left, top);
122 }
123 
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)124 bool CGdiDisplayDriver::UseFoxitStretchEngine(
125     const RetainPtr<CFX_DIBBase>& pSource,
126     uint32_t color,
127     int dest_left,
128     int dest_top,
129     int dest_width,
130     int dest_height,
131     const FX_RECT* pClipRect,
132     const FXDIB_ResampleOptions& options) {
133   FX_RECT bitmap_clip = *pClipRect;
134   if (dest_width < 0)
135     dest_left += dest_width;
136 
137   if (dest_height < 0)
138     dest_top += dest_height;
139 
140   bitmap_clip.Offset(-dest_left, -dest_top);
141   RetainPtr<CFX_DIBitmap> pStretched =
142       pSource->StretchTo(dest_width, dest_height, options, &bitmap_clip);
143   if (!pStretched)
144     return true;
145 
146   FX_RECT src_rect(0, 0, pStretched->GetWidth(), pStretched->GetHeight());
147   return SetDIBits(pStretched, color, src_rect, pClipRect->left, pClipRect->top,
148                    BlendMode::kNormal);
149 }
150 
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)151 bool CGdiDisplayDriver::StretchDIBits(const RetainPtr<CFX_DIBBase>& pSource,
152                                       uint32_t color,
153                                       int dest_left,
154                                       int dest_top,
155                                       int dest_width,
156                                       int dest_height,
157                                       const FX_RECT* pClipRect,
158                                       const FXDIB_ResampleOptions& options,
159                                       BlendMode blend_type) {
160   DCHECK(pSource);
161   DCHECK(pClipRect);
162 
163   if (options.HasAnyOptions() || dest_width > 10000 || dest_width < -10000 ||
164       dest_height > 10000 || dest_height < -10000) {
165     return UseFoxitStretchEngine(pSource, color, dest_left, dest_top,
166                                  dest_width, dest_height, pClipRect, options);
167   }
168   if (pSource->IsMaskFormat()) {
169     FX_RECT image_rect;
170     image_rect.left = dest_width > 0 ? dest_left : dest_left + dest_width;
171     image_rect.right = dest_width > 0 ? dest_left + dest_width : dest_left;
172     image_rect.top = dest_height > 0 ? dest_top : dest_top + dest_height;
173     image_rect.bottom = dest_height > 0 ? dest_top + dest_height : dest_top;
174     FX_RECT clip_rect = image_rect;
175     clip_rect.Intersect(*pClipRect);
176     clip_rect.Offset(-image_rect.left, -image_rect.top);
177     int clip_width = clip_rect.Width(), clip_height = clip_rect.Height();
178     RetainPtr<CFX_DIBitmap> pStretched(pSource->StretchTo(
179         dest_width, dest_height, FXDIB_ResampleOptions(), &clip_rect));
180     if (!pStretched)
181       return true;
182 
183     auto background = pdfium::MakeRetain<CFX_DIBitmap>();
184     if (!background->Create(clip_width, clip_height, FXDIB_Format::kRgb32) ||
185         !GetDIBits(background, image_rect.left + clip_rect.left,
186                    image_rect.top + clip_rect.top) ||
187         !background->CompositeMask(0, 0, clip_width, clip_height, pStretched,
188                                    color, 0, 0, BlendMode::kNormal, nullptr,
189                                    false)) {
190       return false;
191     }
192 
193     FX_RECT src_rect(0, 0, clip_width, clip_height);
194     return SetDIBits(background, 0, src_rect, image_rect.left + clip_rect.left,
195                      image_rect.top + clip_rect.top, BlendMode::kNormal);
196   }
197   if (pSource->IsAlphaFormat()) {
198     auto* pPlatform =
199         static_cast<CWin32Platform*>(CFX_GEModule::Get()->GetPlatform());
200     if (pPlatform->m_GdiplusExt.IsAvailable()) {
201       CFX_DIBExtractor temp(pSource);
202       RetainPtr<CFX_DIBitmap> pBitmap = temp.GetBitmap();
203       if (!pBitmap)
204         return false;
205       return pPlatform->m_GdiplusExt.StretchDIBits(
206           m_hDC, pBitmap, dest_left, dest_top, dest_width, dest_height,
207           pClipRect, FXDIB_ResampleOptions());
208     }
209     return UseFoxitStretchEngine(pSource, color, dest_left, dest_top,
210                                  dest_width, dest_height, pClipRect,
211                                  FXDIB_ResampleOptions());
212   }
213   CFX_DIBExtractor temp(pSource);
214   RetainPtr<CFX_DIBitmap> pBitmap = temp.GetBitmap();
215   if (!pBitmap)
216     return false;
217   return GDI_StretchDIBits(pBitmap, dest_left, dest_top, dest_width,
218                            dest_height, FXDIB_ResampleOptions());
219 }
220 
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)221 bool CGdiDisplayDriver::StartDIBits(const RetainPtr<CFX_DIBBase>& pBitmap,
222                                     int bitmap_alpha,
223                                     uint32_t color,
224                                     const CFX_Matrix& matrix,
225                                     const FXDIB_ResampleOptions& options,
226                                     std::unique_ptr<CFX_ImageRenderer>* handle,
227                                     BlendMode blend_type) {
228   return false;
229 }
230