Initial commit.
[pdfium.git] / core / src / fxge / win32 / fx_win32_dib.cpp
1 // Copyright 2014 PDFium Authors. All rights reserved.\r
2 // Use of this source code is governed by a BSD-style license that can be\r
3 // found in the LICENSE file.\r
4  \r
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com\r
6 \r
7 #include "../../../include/fxge/fx_ge.h"\r
8 #if _FX_OS_ == _FX_WIN32_DESKTOP_ ||  _FX_OS_ == _FX_WIN64_\r
9 #include <windows.h>\r
10 #include "../../../include/fxge/fx_ge_win32.h"\r
11 #include "win32_int.h"\r
12 CFX_ByteString CFX_WindowsDIB::GetBitmapInfo(const CFX_DIBitmap* pBitmap)\r
13 {\r
14     CFX_ByteString result;\r
15     int len = sizeof (BITMAPINFOHEADER);\r
16     if (pBitmap->GetBPP() == 1 || pBitmap->GetBPP() == 8) {\r
17         len += sizeof (DWORD) * (int)(1 << pBitmap->GetBPP());\r
18     }\r
19     BITMAPINFOHEADER* pbmih = (BITMAPINFOHEADER*)result.GetBuffer(len);\r
20     FXSYS_memset32(pbmih, 0, sizeof (BITMAPINFOHEADER));\r
21     pbmih->biSize = sizeof(BITMAPINFOHEADER);\r
22     pbmih->biBitCount = pBitmap->GetBPP();\r
23     pbmih->biCompression = BI_RGB;\r
24     pbmih->biHeight = -(int)pBitmap->GetHeight();\r
25     pbmih->biPlanes = 1;\r
26     pbmih->biWidth = pBitmap->GetWidth();\r
27     if (pBitmap->GetBPP() == 8) {\r
28         FX_DWORD* pPalette = (FX_DWORD*)(pbmih + 1);\r
29         if (pBitmap->GetPalette() == NULL) {\r
30             for (int i = 0; i < 256; i ++) {\r
31                 pPalette[i] = i * 0x010101;\r
32             }\r
33         } else {\r
34             for (int i = 0; i < 256; i ++) {\r
35                 pPalette[i] = pBitmap->GetPalette()[i];\r
36             }\r
37         }\r
38     }\r
39     if (pBitmap->GetBPP() == 1) {\r
40         FX_DWORD* pPalette = (FX_DWORD*)(pbmih + 1);\r
41         if (pBitmap->GetPalette() == NULL) {\r
42             pPalette[0] = 0;\r
43             pPalette[1] = 0xffffff;\r
44         } else {\r
45             pPalette[0] = pBitmap->GetPalette()[0];\r
46             pPalette[1] = pBitmap->GetPalette()[1];\r
47         }\r
48     }\r
49     result.ReleaseBuffer(len);\r
50     return result;\r
51 }\r
52 CFX_DIBitmap* _FX_WindowsDIB_LoadFromBuf(BITMAPINFO* pbmi, LPVOID pData, FX_BOOL bAlpha)\r
53 {\r
54     int width = pbmi->bmiHeader.biWidth;\r
55     int height = pbmi->bmiHeader.biHeight;\r
56     BOOL bBottomUp = TRUE;\r
57     if (height < 0) {\r
58         height = -height;\r
59         bBottomUp = FALSE;\r
60     }\r
61     int pitch = (width * pbmi->bmiHeader.biBitCount + 31) / 32 * 4;\r
62     CFX_DIBitmap* pBitmap = FX_NEW CFX_DIBitmap;\r
63     if (!pBitmap) {\r
64         return NULL;\r
65     }\r
66     FXDIB_Format format = bAlpha ? (FXDIB_Format)(pbmi->bmiHeader.biBitCount + 0x200) : (FXDIB_Format)pbmi->bmiHeader.biBitCount;\r
67     FX_BOOL ret = pBitmap->Create(width, height, format);\r
68     if (!ret) {\r
69         delete pBitmap;\r
70         return NULL;\r
71     }\r
72     FXSYS_memcpy32(pBitmap->GetBuffer(), pData, pitch * height);\r
73     if (bBottomUp) {\r
74         FX_LPBYTE temp_buf = FX_Alloc(FX_BYTE, pitch);\r
75         if (!temp_buf) {\r
76             if (pBitmap) {\r
77                 delete pBitmap;\r
78             }\r
79             return NULL;\r
80         }\r
81         int top = 0, bottom = height - 1;\r
82         while (top < bottom) {\r
83             FXSYS_memcpy32(temp_buf, pBitmap->GetBuffer() + top * pitch, pitch);\r
84             FXSYS_memcpy32(pBitmap->GetBuffer() + top * pitch, pBitmap->GetBuffer() + bottom * pitch, pitch);\r
85             FXSYS_memcpy32(pBitmap->GetBuffer() + bottom * pitch, temp_buf, pitch);\r
86             top ++;\r
87             bottom --;\r
88         }\r
89         FX_Free(temp_buf);\r
90         temp_buf = NULL;\r
91     }\r
92     if (pbmi->bmiHeader.biBitCount == 1) {\r
93         for (int i = 0; i < 2; i ++) {\r
94             pBitmap->SetPaletteEntry(i, ((FX_DWORD*)pbmi->bmiColors)[i] | 0xff000000);\r
95         }\r
96     } else if (pbmi->bmiHeader.biBitCount == 8) {\r
97         for (int i = 0; i < 256; i ++) {\r
98             pBitmap->SetPaletteEntry(i, ((FX_DWORD*)pbmi->bmiColors)[i] | 0xff000000);\r
99         }\r
100     }\r
101     return pBitmap;\r
102 }\r
103 CFX_DIBitmap* CFX_WindowsDIB::LoadFromBuf(BITMAPINFO* pbmi, LPVOID pData)\r
104 {\r
105     return _FX_WindowsDIB_LoadFromBuf(pbmi, pData, FALSE);\r
106 }\r
107 HBITMAP CFX_WindowsDIB::GetDDBitmap(const CFX_DIBitmap* pBitmap, HDC hDC)\r
108 {\r
109     CFX_ByteString info = GetBitmapInfo(pBitmap);\r
110     HBITMAP hBitmap = NULL;\r
111     hBitmap = CreateDIBitmap(hDC, (BITMAPINFOHEADER*)(FX_LPCSTR)info, CBM_INIT,\r
112                              pBitmap->GetBuffer(), (BITMAPINFO*)(FX_LPCSTR)info, DIB_RGB_COLORS);\r
113     return hBitmap;\r
114 }\r
115 void GetBitmapSize(HBITMAP hBitmap, int& w, int& h)\r
116 {\r
117     BITMAP bmp;\r
118     GetObject(hBitmap, sizeof bmp, &bmp);\r
119     w = bmp.bmWidth;\r
120     h = bmp.bmHeight;\r
121 }\r
122 CFX_DIBitmap* CFX_WindowsDIB::LoadFromFile(FX_LPCWSTR filename)\r
123 {\r
124     CWin32Platform* pPlatform = (CWin32Platform*)CFX_GEModule::Get()->GetPlatformData();\r
125     if (pPlatform->m_GdiplusExt.IsAvailable()) {\r
126         WINDIB_Open_Args_ args;\r
127         args.flags = WINDIB_OPEN_PATHNAME;\r
128         args.path_name = filename;\r
129         return pPlatform->m_GdiplusExt.LoadDIBitmap(args);\r
130     }\r
131     HBITMAP hBitmap = (HBITMAP)LoadImageW(NULL, (wchar_t*)filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);\r
132     if (hBitmap == NULL) {\r
133         return NULL;\r
134     }\r
135     HDC hDC = CreateCompatibleDC(NULL);\r
136     int width, height;\r
137     GetBitmapSize(hBitmap, width, height);\r
138     CFX_DIBitmap* pDIBitmap = FX_NEW CFX_DIBitmap;\r
139     if (!pDIBitmap) {\r
140         DeleteDC(hDC);\r
141         return NULL;\r
142     }\r
143     if (!pDIBitmap->Create(width, height, FXDIB_Rgb)) {\r
144         delete pDIBitmap;\r
145         DeleteDC(hDC);\r
146         return NULL;\r
147     }\r
148     CFX_ByteString info = GetBitmapInfo(pDIBitmap);\r
149     int ret = GetDIBits(hDC, hBitmap, 0, height, pDIBitmap->GetBuffer(), (BITMAPINFO*)(FX_LPCSTR)info, DIB_RGB_COLORS);\r
150     if (!ret) {\r
151         if (pDIBitmap) {\r
152             delete pDIBitmap;\r
153         }\r
154         pDIBitmap = NULL;\r
155     }\r
156     DeleteDC(hDC);\r
157     return pDIBitmap;\r
158 }\r
159 CFX_DIBitmap* CFX_WindowsDIB::LoadDIBitmap(WINDIB_Open_Args_ args)\r
160 {\r
161     CWin32Platform* pPlatform = (CWin32Platform*)CFX_GEModule::Get()->GetPlatformData();\r
162     if (pPlatform->m_GdiplusExt.IsAvailable()) {\r
163         return pPlatform->m_GdiplusExt.LoadDIBitmap(args);\r
164     } else if (args.flags == WINDIB_OPEN_MEMORY) {\r
165         return NULL;\r
166     }\r
167     HBITMAP hBitmap = (HBITMAP)LoadImageW(NULL, (wchar_t*)args.path_name, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);\r
168     if (hBitmap == NULL) {\r
169         return NULL;\r
170     }\r
171     HDC hDC = CreateCompatibleDC(NULL);\r
172     int width, height;\r
173     GetBitmapSize(hBitmap, width, height);\r
174     CFX_DIBitmap* pDIBitmap = FX_NEW CFX_DIBitmap;\r
175     if (!pDIBitmap) {\r
176         DeleteDC(hDC);\r
177         return NULL;\r
178     }\r
179     if (!pDIBitmap->Create(width, height, FXDIB_Rgb)) {\r
180         delete pDIBitmap;\r
181         DeleteDC(hDC);\r
182         return NULL;\r
183     }\r
184     CFX_ByteString info = GetBitmapInfo(pDIBitmap);\r
185     int ret = GetDIBits(hDC, hBitmap, 0, height, pDIBitmap->GetBuffer(), (BITMAPINFO*)(FX_LPCSTR)info, DIB_RGB_COLORS);\r
186     if (!ret) {\r
187         if (pDIBitmap) {\r
188             delete pDIBitmap;\r
189         }\r
190         pDIBitmap = NULL;\r
191     }\r
192     DeleteDC(hDC);\r
193     return pDIBitmap;\r
194 }\r
195 CFX_DIBitmap* CFX_WindowsDIB::LoadFromDDB(HDC hDC, HBITMAP hBitmap, FX_DWORD* pPalette, FX_DWORD palsize)\r
196 {\r
197     FX_BOOL bCreatedDC = hDC == NULL;\r
198     if (hDC == NULL) {\r
199         hDC = CreateCompatibleDC(NULL);\r
200     }\r
201     BITMAPINFOHEADER bmih;\r
202     FXSYS_memset32(&bmih, 0, sizeof bmih);\r
203     bmih.biSize = sizeof bmih;\r
204     GetDIBits(hDC, hBitmap, 0, 0, NULL, (BITMAPINFO*)&bmih, DIB_RGB_COLORS);\r
205     int width = bmih.biWidth;\r
206     int height = abs(bmih.biHeight);\r
207     bmih.biHeight = -height;\r
208     bmih.biCompression = BI_RGB;\r
209     CFX_DIBitmap* pDIBitmap = FX_NEW CFX_DIBitmap;\r
210     if (!pDIBitmap) {\r
211         return NULL;\r
212     }\r
213     int ret = 0;\r
214     if (bmih.biBitCount == 1 || bmih.biBitCount == 8) {\r
215         int size = sizeof (BITMAPINFOHEADER) + 8;\r
216         if (bmih.biBitCount == 8) {\r
217             size += sizeof (FX_DWORD) * 254;\r
218         }\r
219         BITMAPINFO* pbmih = (BITMAPINFO*)FX_Alloc(FX_BYTE, size);\r
220         if (!pbmih) {\r
221             delete pDIBitmap;\r
222             if (bCreatedDC) {\r
223                 DeleteDC(hDC);\r
224             }\r
225             return NULL;\r
226         }\r
227         FXSYS_memset32(pbmih, 0, sizeof (BITMAPINFOHEADER));\r
228         pbmih->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);\r
229         pbmih->bmiHeader.biBitCount = bmih.biBitCount;\r
230         pbmih->bmiHeader.biCompression = BI_RGB;\r
231         pbmih->bmiHeader.biHeight = -height;\r
232         pbmih->bmiHeader.biPlanes = 1;\r
233         pbmih->bmiHeader.biWidth = bmih.biWidth;\r
234         if (!pDIBitmap->Create(bmih.biWidth, height, bmih.biBitCount == 1 ? FXDIB_1bppRgb : FXDIB_8bppRgb)) {\r
235             delete pDIBitmap;\r
236             FX_Free(pbmih);\r
237             if (bCreatedDC) {\r
238                 DeleteDC(hDC);\r
239             }\r
240             return NULL;\r
241         }\r
242         ret = GetDIBits(hDC, hBitmap, 0, height, pDIBitmap->GetBuffer(), (BITMAPINFO*)pbmih, DIB_RGB_COLORS);\r
243         FX_Free(pbmih);\r
244         pbmih = NULL;\r
245         pDIBitmap->CopyPalette(pPalette, palsize);\r
246     } else {\r
247         if (bmih.biBitCount <= 24) {\r
248             bmih.biBitCount = 24;\r
249         } else {\r
250             bmih.biBitCount = 32;\r
251         }\r
252         if (!pDIBitmap->Create(bmih.biWidth, height, bmih.biBitCount == 24 ? FXDIB_Rgb : FXDIB_Rgb32)) {\r
253             delete pDIBitmap;\r
254             if (bCreatedDC) {\r
255                 DeleteDC(hDC);\r
256             }\r
257             return NULL;\r
258         }\r
259         ret = GetDIBits(hDC, hBitmap, 0, height, pDIBitmap->GetBuffer(), (BITMAPINFO*)&bmih, DIB_RGB_COLORS);\r
260         if (ret != 0 && bmih.biBitCount == 32) {\r
261             int pitch = pDIBitmap->GetPitch();\r
262             for (int row = 0; row < height; row ++) {\r
263                 FX_BYTE* dest_scan = (FX_BYTE*)(pDIBitmap->GetBuffer() + row * pitch);\r
264                 for (int col = 0; col < width; col++) {\r
265                     dest_scan[3] = 255;\r
266                     dest_scan += 4;\r
267                 }\r
268             }\r
269         }\r
270     }\r
271     if (ret == 0) {\r
272         if (pDIBitmap) {\r
273             delete pDIBitmap;\r
274         }\r
275         pDIBitmap = NULL;\r
276     }\r
277     if (bCreatedDC) {\r
278         DeleteDC(hDC);\r
279     }\r
280     return pDIBitmap;\r
281 }\r
282 CFX_WindowsDIB::CFX_WindowsDIB(HDC hDC, int width, int height)\r
283 {\r
284     Create(width, height, FXDIB_Rgb, (FX_LPBYTE)1);\r
285     BITMAPINFOHEADER bmih;\r
286     FXSYS_memset32(&bmih, 0, sizeof bmih);\r
287     bmih.biSize = sizeof bmih;\r
288     bmih.biBitCount = 24;\r
289     bmih.biHeight = -height;\r
290     bmih.biPlanes = 1;\r
291     bmih.biWidth = width;\r
292     m_hBitmap = CreateDIBSection(hDC, (BITMAPINFO*)&bmih, DIB_RGB_COLORS, (LPVOID*)&m_pBuffer, NULL, 0);\r
293     m_hMemDC = CreateCompatibleDC(hDC);\r
294     m_hOldBitmap = (HBITMAP)SelectObject(m_hMemDC, m_hBitmap);\r
295 }\r
296 CFX_WindowsDIB::~CFX_WindowsDIB()\r
297 {\r
298     SelectObject(m_hMemDC, m_hOldBitmap);\r
299     DeleteDC(m_hMemDC);\r
300     DeleteObject(m_hBitmap);\r
301 }\r
302 void CFX_WindowsDIB::LoadFromDevice(HDC hDC, int left, int top)\r
303 {\r
304     ::BitBlt(m_hMemDC, 0, 0, m_Width, m_Height, hDC, left, top, SRCCOPY);\r
305 }\r
306 void CFX_WindowsDIB::SetToDevice(HDC hDC, int left, int top)\r
307 {\r
308     ::BitBlt(hDC, left, top, m_Width, m_Height, m_hMemDC, 0, 0, SRCCOPY);\r
309 }\r
310 #endif\r