xref: /aosp_15_r20/external/pdfium/core/fxge/win32/cgdi_display_driver.cpp (revision 3ac0a46f773bac49fa9476ec2b1cf3f8da5ec3a4)
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_dibbase.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,
55                       pBitmap->GetWritableBuffer().data(), &bmi,
56                       DIB_RGB_COLORS) == height;
57   } else {
58     auto bitmap = pdfium::MakeRetain<CFX_DIBitmap>();
59     if (bitmap->Create(width, height, FXDIB_Format::kRgb)) {
60       bmi.bmiHeader.biBitCount = 24;
61       ::GetDIBits(hDCMemory, hbmp, 0, height,
62                   bitmap->GetWritableBuffer().data(), &bmi, DIB_RGB_COLORS);
63       ret = pBitmap->TransferBitmap(0, 0, width, height, bitmap, 0, 0);
64     } else {
65       ret = false;
66     }
67   }
68   if (ret && pBitmap->IsAlphaFormat())
69     pBitmap->SetUniformOpaqueAlpha();
70 
71   DeleteObject(hbmp);
72   DeleteObject(hDCMemory);
73   return ret;
74 }
75 
SetDIBits(const RetainPtr<CFX_DIBBase> & pSource,uint32_t color,const FX_RECT & src_rect,int left,int top,BlendMode blend_type)76 bool CGdiDisplayDriver::SetDIBits(const RetainPtr<CFX_DIBBase>& pSource,
77                                   uint32_t color,
78                                   const FX_RECT& src_rect,
79                                   int left,
80                                   int top,
81                                   BlendMode blend_type) {
82   DCHECK_EQ(blend_type, BlendMode::kNormal);
83   if (pSource->IsMaskFormat()) {
84     int width = pSource->GetWidth(), height = pSource->GetHeight();
85     int alpha = FXARGB_A(color);
86     if (pSource->GetBPP() != 1 || alpha != 255) {
87       auto background = pdfium::MakeRetain<CFX_DIBitmap>();
88       if (!background->Create(width, height, FXDIB_Format::kRgb32) ||
89           !GetDIBits(background, left, top) ||
90           !background->CompositeMask(0, 0, width, height, pSource, color, 0, 0,
91                                      BlendMode::kNormal, nullptr, false)) {
92         return false;
93       }
94       FX_RECT alpha_src_rect(0, 0, width, height);
95       return SetDIBits(background, 0, alpha_src_rect, left, top,
96                        BlendMode::kNormal);
97     }
98     FX_RECT clip_rect(left, top, left + src_rect.Width(),
99                       top + src_rect.Height());
100     return StretchDIBits(pSource, color, left - src_rect.left,
101                          top - src_rect.top, width, height, &clip_rect,
102                          FXDIB_ResampleOptions(), BlendMode::kNormal);
103   }
104   int width = src_rect.Width();
105   int height = src_rect.Height();
106   if (pSource->IsAlphaFormat()) {
107     auto bitmap = pdfium::MakeRetain<CFX_DIBitmap>();
108     if (!bitmap->Create(width, height, FXDIB_Format::kRgb) ||
109         !GetDIBits(bitmap, left, top) ||
110         !bitmap->CompositeBitmap(0, 0, width, height, pSource, src_rect.left,
111                                  src_rect.top, BlendMode::kNormal, nullptr,
112                                  false)) {
113       return false;
114     }
115     FX_RECT alpha_src_rect(0, 0, width, height);
116     return SetDIBits(bitmap, 0, alpha_src_rect, left, top, BlendMode::kNormal);
117   }
118   return GDI_SetDIBits(pSource, src_rect, left, top);
119 }
120 
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)121 bool CGdiDisplayDriver::UseFoxitStretchEngine(
122     const RetainPtr<CFX_DIBBase>& pSource,
123     uint32_t color,
124     int dest_left,
125     int dest_top,
126     int dest_width,
127     int dest_height,
128     const FX_RECT* pClipRect,
129     const FXDIB_ResampleOptions& options) {
130   FX_RECT bitmap_clip = *pClipRect;
131   if (dest_width < 0)
132     dest_left += dest_width;
133 
134   if (dest_height < 0)
135     dest_top += dest_height;
136 
137   bitmap_clip.Offset(-dest_left, -dest_top);
138   RetainPtr<CFX_DIBBase> pStretched =
139       pSource->StretchTo(dest_width, dest_height, options, &bitmap_clip);
140   if (!pStretched)
141     return true;
142 
143   FX_RECT src_rect(0, 0, pStretched->GetWidth(), pStretched->GetHeight());
144   return SetDIBits(pStretched, color, src_rect, pClipRect->left, pClipRect->top,
145                    BlendMode::kNormal);
146 }
147 
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)148 bool CGdiDisplayDriver::StretchDIBits(const RetainPtr<CFX_DIBBase>& pSource,
149                                       uint32_t color,
150                                       int dest_left,
151                                       int dest_top,
152                                       int dest_width,
153                                       int dest_height,
154                                       const FX_RECT* pClipRect,
155                                       const FXDIB_ResampleOptions& options,
156                                       BlendMode blend_type) {
157   DCHECK(pSource);
158   DCHECK(pClipRect);
159 
160   if (options.HasAnyOptions() || dest_width > 10000 || dest_width < -10000 ||
161       dest_height > 10000 || dest_height < -10000) {
162     return UseFoxitStretchEngine(pSource, color, dest_left, dest_top,
163                                  dest_width, dest_height, pClipRect, options);
164   }
165   if (pSource->IsMaskFormat()) {
166     FX_RECT image_rect;
167     image_rect.left = dest_width > 0 ? dest_left : dest_left + dest_width;
168     image_rect.right = dest_width > 0 ? dest_left + dest_width : dest_left;
169     image_rect.top = dest_height > 0 ? dest_top : dest_top + dest_height;
170     image_rect.bottom = dest_height > 0 ? dest_top + dest_height : dest_top;
171     FX_RECT clip_rect = image_rect;
172     clip_rect.Intersect(*pClipRect);
173     clip_rect.Offset(-image_rect.left, -image_rect.top);
174     int clip_width = clip_rect.Width(), clip_height = clip_rect.Height();
175     RetainPtr<CFX_DIBitmap> pStretched(pSource->StretchTo(
176         dest_width, dest_height, FXDIB_ResampleOptions(), &clip_rect));
177     if (!pStretched)
178       return true;
179 
180     auto background = pdfium::MakeRetain<CFX_DIBitmap>();
181     if (!background->Create(clip_width, clip_height, FXDIB_Format::kRgb32) ||
182         !GetDIBits(background, image_rect.left + clip_rect.left,
183                    image_rect.top + clip_rect.top) ||
184         !background->CompositeMask(0, 0, clip_width, clip_height, pStretched,
185                                    color, 0, 0, BlendMode::kNormal, nullptr,
186                                    false)) {
187       return false;
188     }
189 
190     FX_RECT src_rect(0, 0, clip_width, clip_height);
191     return SetDIBits(background, 0, src_rect, image_rect.left + clip_rect.left,
192                      image_rect.top + clip_rect.top, BlendMode::kNormal);
193   }
194   if (pSource->IsAlphaFormat()) {
195     auto* pPlatform =
196         static_cast<CWin32Platform*>(CFX_GEModule::Get()->GetPlatform());
197     if (pPlatform->m_GdiplusExt.IsAvailable()) {
198       return pPlatform->m_GdiplusExt.StretchDIBits(
199           m_hDC, pSource, dest_left, dest_top, dest_width, dest_height,
200           pClipRect, FXDIB_ResampleOptions());
201     }
202     return UseFoxitStretchEngine(pSource, color, dest_left, dest_top,
203                                  dest_width, dest_height, pClipRect,
204                                  FXDIB_ResampleOptions());
205   }
206   return GDI_StretchDIBits(pSource, dest_left, dest_top, dest_width,
207                            dest_height, FXDIB_ResampleOptions());
208 }
209 
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)210 bool CGdiDisplayDriver::StartDIBits(const RetainPtr<CFX_DIBBase>& pBitmap,
211                                     int bitmap_alpha,
212                                     uint32_t color,
213                                     const CFX_Matrix& matrix,
214                                     const FXDIB_ResampleOptions& options,
215                                     std::unique_ptr<CFX_ImageRenderer>* handle,
216                                     BlendMode blend_type) {
217   return false;
218 }
219