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