diff options
Diffstat (limited to 'core/fxge/win32')
-rw-r--r-- | core/fxge/win32/dwrite_int.h | 66 | ||||
-rw-r--r-- | core/fxge/win32/fx_win32_device.cpp | 1372 | ||||
-rw-r--r-- | core/fxge/win32/fx_win32_dib.cpp | 289 | ||||
-rw-r--r-- | core/fxge/win32/fx_win32_dwrite.cpp | 410 | ||||
-rw-r--r-- | core/fxge/win32/fx_win32_gdipext.cpp | 1518 | ||||
-rw-r--r-- | core/fxge/win32/fx_win32_print.cpp | 473 | ||||
-rw-r--r-- | core/fxge/win32/win32_int.h | 369 |
7 files changed, 4497 insertions, 0 deletions
diff --git a/core/fxge/win32/dwrite_int.h b/core/fxge/win32/dwrite_int.h new file mode 100644 index 0000000000..62672b2387 --- /dev/null +++ b/core/fxge/win32/dwrite_int.h @@ -0,0 +1,66 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#ifndef CORE_FXGE_WIN32_DWRITE_INT_H_ +#define CORE_FXGE_WIN32_DWRITE_INT_H_ + +#ifndef DECLSPEC_UUID +#if (_MSC_VER >= 1100) && defined(__cplusplus) +#define DECLSPEC_UUID(x) __declspec(uuid(x)) +#else +#define DECLSPEC_UUID(x) +#endif +#endif +#ifndef DECLSPEC_NOVTABLE +#if (_MSC_VER >= 1100) && defined(__cplusplus) +#define DECLSPEC_NOVTABLE __declspec(novtable) +#else +#define DECLSPEC_NOVTABLE +#endif +#endif +#if (WINVER < 0x0500) +#ifndef _MAC +DECLARE_HANDLE(HMONITOR); +#endif +#endif +class CDWriteExt { + public: + CDWriteExt(); + ~CDWriteExt(); + + void Load(); + void Unload(); + + FX_BOOL IsAvailable() { return m_pDWriteFactory != NULL; } + + void* DwCreateFontFaceFromStream(uint8_t* pData, + FX_DWORD size, + int simulation_style); + FX_BOOL DwCreateRenderingTarget(CFX_DIBitmap* pSrc, void** renderTarget); + void DwDeleteRenderingTarget(void* renderTarget); + FX_BOOL DwRendingString(void* renderTarget, + CFX_ClipRgn* pClipRgn, + FX_RECT& stringRect, + CFX_Matrix* pMatrix, + void* font, + FX_FLOAT font_size, + FX_ARGB text_color, + int glyph_count, + unsigned short* glyph_indices, + FX_FLOAT baselineOriginX, + FX_FLOAT baselineOriginY, + void* glyph_offsets, + FX_FLOAT* glyph_advances); + void DwDeleteFont(void* pFont); + + protected: + void* m_hModule; + void* m_pDWriteFactory; + void* m_pDwFontContext; + void* m_pDwTextRenderer; +}; + +#endif // CORE_FXGE_WIN32_DWRITE_INT_H_ diff --git a/core/fxge/win32/fx_win32_device.cpp b/core/fxge/win32/fx_win32_device.cpp new file mode 100644 index 0000000000..c7afab39a7 --- /dev/null +++ b/core/fxge/win32/fx_win32_device.cpp @@ -0,0 +1,1372 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "core/include/fxge/fx_ge.h" + +#if _FX_OS_ == _FX_WIN32_DESKTOP_ || _FX_OS_ == _FX_WIN64_DESKTOP_ +#include <crtdbg.h> + +#include "core/fxge/agg/fx_agg_driver.h" +#include "core/fxge/dib/dib_int.h" +#include "core/fxge/ge/fx_text_int.h" +#include "core/fxge/win32/dwrite_int.h" +#include "core/fxge/win32/win32_int.h" +#include "core/include/fxcodec/fx_codec.h" +#include "core/include/fxge/fx_freetype.h" +#include "core/include/fxge/fx_ge_win32.h" +#include "third_party/base/stl_util.h" + +class CFX_Win32FallbackFontInfo final : public CFX_FolderFontInfo { + public: + void* MapFont(int weight, + FX_BOOL bItalic, + int charset, + int pitch_family, + const FX_CHAR* family, + int& iExact) override; +}; +class CFX_Win32FontInfo final : public IFX_SystemFontInfo { + public: + CFX_Win32FontInfo(); + ~CFX_Win32FontInfo() override; + + // IFX_SystemFontInfo + void Release() override; + FX_BOOL EnumFontList(CFX_FontMapper* pMapper) override; + void* MapFont(int weight, + FX_BOOL bItalic, + int charset, + int pitch_family, + const FX_CHAR* face, + int& iExact) override; + void* GetFont(const FX_CHAR* face) override { return NULL; } + FX_DWORD GetFontData(void* hFont, + FX_DWORD table, + uint8_t* buffer, + FX_DWORD size) override; + FX_BOOL GetFaceName(void* hFont, CFX_ByteString& name) override; + FX_BOOL GetFontCharset(void* hFont, int& charset) override; + void DeleteFont(void* hFont) override; + + FX_BOOL IsOpenTypeFromDiv(const LOGFONTA* plf); + FX_BOOL IsSupportFontFormDiv(const LOGFONTA* plf); + void AddInstalledFont(const LOGFONTA* plf, FX_DWORD FontType); + void GetGBPreference(CFX_ByteString& face, int weight, int picth_family); + void GetJapanesePreference(CFX_ByteString& face, + int weight, + int picth_family); + CFX_ByteString FindFont(const CFX_ByteString& name); + HDC m_hDC; + CFX_FontMapper* m_pMapper; + CFX_ByteString m_LastFamily; + CFX_ByteString m_KaiTi, m_FangSong; +}; + +CFX_Win32FontInfo::CFX_Win32FontInfo() { + m_hDC = CreateCompatibleDC(NULL); +} +CFX_Win32FontInfo::~CFX_Win32FontInfo() { + m_pMapper = NULL; +} +void CFX_Win32FontInfo::Release() { + DeleteDC(m_hDC); + delete this; +} +#define TT_MAKE_TAG(x1, x2, x3, x4) \ + (((FX_DWORD)x1 << 24) | ((FX_DWORD)x2 << 16) | ((FX_DWORD)x3 << 8) | \ + (FX_DWORD)x4) +FX_BOOL CFX_Win32FontInfo::IsOpenTypeFromDiv(const LOGFONTA* plf) { + HFONT hFont = CreateFontIndirectA(plf); + FX_BOOL ret = FALSE; + FX_DWORD font_size = GetFontData(hFont, 0, NULL, 0); + if (font_size != GDI_ERROR && font_size >= sizeof(FX_DWORD)) { + FX_DWORD lVersion = 0; + GetFontData(hFont, 0, (uint8_t*)(&lVersion), sizeof(FX_DWORD)); + lVersion = (((FX_DWORD)(uint8_t)(lVersion)) << 24) | + ((FX_DWORD)((uint8_t)(lVersion >> 8))) << 16 | + ((FX_DWORD)((uint8_t)(lVersion >> 16))) << 8 | + ((uint8_t)(lVersion >> 24)); + if (lVersion == TT_MAKE_TAG('O', 'T', 'T', 'O') || lVersion == 0x00010000 || + lVersion == TT_MAKE_TAG('t', 't', 'c', 'f') || + lVersion == TT_MAKE_TAG('t', 'r', 'u', 'e') || lVersion == 0x00020000) { + ret = TRUE; + } + } + DeleteFont(hFont); + return ret; +} +FX_BOOL CFX_Win32FontInfo::IsSupportFontFormDiv(const LOGFONTA* plf) { + HFONT hFont = CreateFontIndirectA(plf); + FX_BOOL ret = FALSE; + FX_DWORD font_size = GetFontData(hFont, 0, NULL, 0); + if (font_size != GDI_ERROR && font_size >= sizeof(FX_DWORD)) { + FX_DWORD lVersion = 0; + GetFontData(hFont, 0, (uint8_t*)(&lVersion), sizeof(FX_DWORD)); + lVersion = (((FX_DWORD)(uint8_t)(lVersion)) << 24) | + ((FX_DWORD)((uint8_t)(lVersion >> 8))) << 16 | + ((FX_DWORD)((uint8_t)(lVersion >> 16))) << 8 | + ((uint8_t)(lVersion >> 24)); + if (lVersion == TT_MAKE_TAG('O', 'T', 'T', 'O') || lVersion == 0x00010000 || + lVersion == TT_MAKE_TAG('t', 't', 'c', 'f') || + lVersion == TT_MAKE_TAG('t', 'r', 'u', 'e') || lVersion == 0x00020000) { + ret = TRUE; + } else if ((lVersion & 0xFFFF0000) == TT_MAKE_TAG(0x80, 0x01, 0x00, 0x00) || + (lVersion & 0xFFFF0000) == TT_MAKE_TAG('%', '!', 0, 0)) { + ret = TRUE; + } + } + DeleteFont(hFont); + return ret; +} +void CFX_Win32FontInfo::AddInstalledFont(const LOGFONTA* plf, + FX_DWORD FontType) { + CFX_ByteString name(plf->lfFaceName); + if (name[0] == '@') { + return; + } + if (name == m_LastFamily) { + m_pMapper->AddInstalledFont(name, plf->lfCharSet); + return; + } + if (!(FontType & TRUETYPE_FONTTYPE) && !(FontType & DEVICE_FONTTYPE)) { + return; + } + if (!(FontType & TRUETYPE_FONTTYPE)) { + if (!IsSupportFontFormDiv(plf)) { + return; + } + } + m_pMapper->AddInstalledFont(name, plf->lfCharSet); + m_LastFamily = name; +} +static int CALLBACK FontEnumProc(const LOGFONTA* plf, + const TEXTMETRICA* lpntme, + FX_DWORD FontType, + LPARAM lParam) { + CFX_Win32FontInfo* pFontInfo = (CFX_Win32FontInfo*)lParam; + if (pFontInfo->m_pMapper->GetFontEnumerator()) { + pFontInfo->m_pMapper->GetFontEnumerator()->HitFont(); + } + pFontInfo->AddInstalledFont(plf, FontType); + return 1; +} +FX_BOOL CFX_Win32FontInfo::EnumFontList(CFX_FontMapper* pMapper) { + m_pMapper = pMapper; + LOGFONTA lf; + FXSYS_memset(&lf, 0, sizeof(LOGFONTA)); + lf.lfCharSet = DEFAULT_CHARSET; + lf.lfFaceName[0] = 0; + lf.lfPitchAndFamily = 0; + EnumFontFamiliesExA(m_hDC, &lf, (FONTENUMPROCA)FontEnumProc, (uintptr_t) this, + 0); + if (pMapper->GetFontEnumerator()) { + pMapper->GetFontEnumerator()->Finish(); + } + return TRUE; +} +static const struct { + const FX_CHAR* m_pFaceName; + const FX_CHAR* m_pVariantName; +} VariantNames[] = { + {"DFKai-SB", "\x19\x6A\x77\x69\xD4\x9A"}, +}; +static const struct { + const FX_CHAR* m_pName; + const FX_CHAR* m_pWinName; + FX_BOOL m_bBold; + FX_BOOL m_bItalic; +} Base14Substs[] = { + {"Courier", "Courier New", FALSE, FALSE}, + {"Courier-Bold", "Courier New", TRUE, FALSE}, + {"Courier-BoldOblique", "Courier New", TRUE, TRUE}, + {"Courier-Oblique", "Courier New", FALSE, TRUE}, + {"Helvetica", "Arial", FALSE, FALSE}, + {"Helvetica-Bold", "Arial", TRUE, FALSE}, + {"Helvetica-BoldOblique", "Arial", TRUE, TRUE}, + {"Helvetica-Oblique", "Arial", FALSE, TRUE}, + {"Times-Roman", "Times New Roman", FALSE, FALSE}, + {"Times-Bold", "Times New Roman", TRUE, FALSE}, + {"Times-BoldItalic", "Times New Roman", TRUE, TRUE}, + {"Times-Italic", "Times New Roman", FALSE, TRUE}, +}; +CFX_ByteString CFX_Win32FontInfo::FindFont(const CFX_ByteString& name) { + if (!m_pMapper) { + return name; + } + int nFonts = pdfium::CollectionSize<int>(m_pMapper->m_InstalledTTFonts); + for (int i = 0; i < nFonts; i++) { + CFX_ByteString thisname = m_pMapper->m_InstalledTTFonts[i]; + if (thisname[0] == ' ') { + if (thisname.Mid(1, name.GetLength()) == name) { + return m_pMapper->m_InstalledTTFonts[i + 1]; + } + } else if (thisname.Left(name.GetLength()) == name) { + return m_pMapper->m_InstalledTTFonts[i]; + } + } + return CFX_ByteString(); +} +void* CFX_Win32FallbackFontInfo::MapFont(int weight, + FX_BOOL bItalic, + int charset, + int pitch_family, + const FX_CHAR* cstr_face, + int& iExact) { + void* font = GetSubstFont(cstr_face); + if (font) { + iExact = 1; + return font; + } + FX_BOOL bCJK = TRUE; + switch (charset) { + case FXFONT_SHIFTJIS_CHARSET: + case FXFONT_GB2312_CHARSET: + case FXFONT_CHINESEBIG5_CHARSET: + case FXFONT_HANGEUL_CHARSET: + default: + bCJK = FALSE; + break; + } + return FindFont(weight, bItalic, charset, pitch_family, cstr_face, !bCJK); +} +struct _FontNameMap { + const FX_CHAR* m_pSubFontName; + const FX_CHAR* m_pSrcFontName; +}; +const _FontNameMap g_JpFontNameMap[] = { + {"MS Mincho", "Heiseimin-W3"}, + {"MS Gothic", "Jun101-Light"}, +}; +extern "C" { +static int compareString(const void* key, const void* element) { + return FXSYS_stricmp((const FX_CHAR*)key, + ((_FontNameMap*)element)->m_pSrcFontName); +} +} +FX_BOOL _GetSubFontName(CFX_ByteString& name) { + int size = sizeof g_JpFontNameMap; + void* pFontnameMap = (void*)g_JpFontNameMap; + _FontNameMap* found = (_FontNameMap*)FXSYS_bsearch( + name.c_str(), pFontnameMap, size / sizeof(_FontNameMap), + sizeof(_FontNameMap), compareString); + if (!found) { + return FALSE; + } + name = found->m_pSubFontName; + return TRUE; +} +void CFX_Win32FontInfo::GetGBPreference(CFX_ByteString& face, + int weight, + int picth_family) { + if (face.Find("KaiTi") >= 0 || face.Find("\xbf\xac") >= 0) { + if (m_KaiTi.IsEmpty()) { + m_KaiTi = FindFont("KaiTi"); + if (m_KaiTi.IsEmpty()) { + m_KaiTi = "SimSun"; + } + } + face = m_KaiTi; + } else if (face.Find("FangSong") >= 0 || face.Find("\xb7\xc2\xcb\xce") >= 0) { + if (m_FangSong.IsEmpty()) { + m_FangSong = FindFont("FangSong"); + if (m_FangSong.IsEmpty()) { + m_FangSong = "SimSun"; + } + } + face = m_FangSong; + } else if (face.Find("SimSun") >= 0 || face.Find("\xcb\xce") >= 0) { + face = "SimSun"; + } else if (face.Find("SimHei") >= 0 || face.Find("\xba\xda") >= 0) { + face = "SimHei"; + } else if (!(picth_family & FF_ROMAN) && weight > 550) { + face = "SimHei"; + } else { + face = "SimSun"; + } +} +void CFX_Win32FontInfo::GetJapanesePreference(CFX_ByteString& face, + int weight, + int picth_family) { + if (face.Find("Gothic") >= 0 || + face.Find("\x83\x53\x83\x56\x83\x62\x83\x4e") >= 0) { + if (face.Find("PGothic") >= 0 || + face.Find("\x82\x6f\x83\x53\x83\x56\x83\x62\x83\x4e") >= 0) { + face = "MS PGothic"; + } else if (face.Find("UI Gothic") >= 0) { + face = "MS UI Gothic"; + } else { + if (face.Find("HGSGothicM") >= 0 || face.Find("HGMaruGothicMPRO") >= 0) { + face = "MS PGothic"; + } else { + face = "MS Gothic"; + } + } + return; + } + if (face.Find("Mincho") >= 0 || face.Find("\x96\xbe\x92\xa9") >= 0) { + if (face.Find("PMincho") >= 0 || + face.Find("\x82\x6f\x96\xbe\x92\xa9") >= 0) { + face = "MS PMincho"; + } else { + face = "MS Mincho"; + } + return; + } + if (_GetSubFontName(face)) { + return; + } + if (!(picth_family & FF_ROMAN) && weight > 400) { + face = "MS PGothic"; + } else { + face = "MS PMincho"; + } +} +void* CFX_Win32FontInfo::MapFont(int weight, + FX_BOOL bItalic, + int charset, + int pitch_family, + const FX_CHAR* cstr_face, + int& iExact) { + CFX_ByteString face = cstr_face; + int iBaseFont; + for (iBaseFont = 0; iBaseFont < 12; iBaseFont++) + if (face == CFX_ByteStringC(Base14Substs[iBaseFont].m_pName)) { + face = Base14Substs[iBaseFont].m_pWinName; + weight = Base14Substs[iBaseFont].m_bBold ? FW_BOLD : FW_NORMAL; + bItalic = Base14Substs[iBaseFont].m_bItalic; + iExact = TRUE; + break; + } + if (charset == ANSI_CHARSET || charset == SYMBOL_CHARSET) { + charset = DEFAULT_CHARSET; + } + int subst_pitch_family = pitch_family; + switch (charset) { + case SHIFTJIS_CHARSET: + subst_pitch_family = FF_ROMAN; + break; + case CHINESEBIG5_CHARSET: + case HANGUL_CHARSET: + case GB2312_CHARSET: + subst_pitch_family = 0; + break; + } + HFONT hFont = + ::CreateFontA(-10, 0, 0, 0, weight, bItalic, 0, 0, charset, + OUT_TT_ONLY_PRECIS, 0, 0, subst_pitch_family, face); + char facebuf[100]; + HFONT hOldFont = (HFONT)::SelectObject(m_hDC, hFont); + ::GetTextFaceA(m_hDC, 100, facebuf); + ::SelectObject(m_hDC, hOldFont); + if (face.EqualNoCase(facebuf)) { + return hFont; + } + int iCount = sizeof(VariantNames) / sizeof(VariantNames[0]); + for (int i = 0; i < iCount; ++i) { + if (face == VariantNames[i].m_pFaceName) { + CFX_WideString wsFace = CFX_WideString::FromLocal(facebuf); + const unsigned short* pName = + (const unsigned short*)VariantNames[i].m_pVariantName; + FX_STRSIZE len = CFX_WideString::WStringLength(pName); + CFX_WideString wsName = CFX_WideString::FromUTF16LE(pName, len); + if (wsFace == wsName) { + return hFont; + } + } + } + ::DeleteObject(hFont); + if (charset == DEFAULT_CHARSET) { + return NULL; + } + switch (charset) { + case SHIFTJIS_CHARSET: + GetJapanesePreference(face, weight, pitch_family); + break; + case GB2312_CHARSET: + GetGBPreference(face, weight, pitch_family); + break; + case HANGUL_CHARSET: + face = "Gulim"; + break; + case CHINESEBIG5_CHARSET: + if (face.Find("MSung") >= 0) { + face = "MingLiU"; + } else { + face = "PMingLiU"; + } + break; + } + hFont = ::CreateFontA(-10, 0, 0, 0, weight, bItalic, 0, 0, charset, + OUT_TT_ONLY_PRECIS, 0, 0, subst_pitch_family, face); + return hFont; +} +void CFX_Win32FontInfo::DeleteFont(void* hFont) { + ::DeleteObject(hFont); +} +FX_DWORD CFX_Win32FontInfo::GetFontData(void* hFont, + FX_DWORD table, + uint8_t* buffer, + FX_DWORD size) { + HFONT hOldFont = (HFONT)::SelectObject(m_hDC, (HFONT)hFont); + table = FXDWORD_FROM_MSBFIRST(table); + size = ::GetFontData(m_hDC, table, 0, buffer, size); + ::SelectObject(m_hDC, hOldFont); + if (size == GDI_ERROR) { + return 0; + } + return size; +} +FX_BOOL CFX_Win32FontInfo::GetFaceName(void* hFont, CFX_ByteString& name) { + char facebuf[100]; + HFONT hOldFont = (HFONT)::SelectObject(m_hDC, (HFONT)hFont); + int ret = ::GetTextFaceA(m_hDC, 100, facebuf); + ::SelectObject(m_hDC, hOldFont); + if (ret == 0) { + return FALSE; + } + name = facebuf; + return TRUE; +} +FX_BOOL CFX_Win32FontInfo::GetFontCharset(void* hFont, int& charset) { + TEXTMETRIC tm; + HFONT hOldFont = (HFONT)::SelectObject(m_hDC, (HFONT)hFont); + ::GetTextMetrics(m_hDC, &tm); + ::SelectObject(m_hDC, hOldFont); + charset = tm.tmCharSet; + return TRUE; +} +static FX_BOOL IsGDIEnabled() { + // If GDI is disabled then GetDC for the desktop will fail. + HDC hdc = ::GetDC(NULL); + if (hdc) { + ::ReleaseDC(NULL, hdc); + return TRUE; + } + return FALSE; +} +IFX_SystemFontInfo* IFX_SystemFontInfo::CreateDefault(const char** pUnused) { + if (IsGDIEnabled()) { + return new CFX_Win32FontInfo; + } + // Select the fallback font information class if GDI is disabled. + CFX_Win32FallbackFontInfo* pInfoFallback = new CFX_Win32FallbackFontInfo; + // Construct the font path manually, SHGetKnownFolderPath won't work under + // a restrictive sandbox. + CHAR windows_path[MAX_PATH] = {}; + DWORD path_len = ::GetWindowsDirectoryA(windows_path, MAX_PATH); + if (path_len > 0 && path_len < MAX_PATH) { + CFX_ByteString fonts_path(windows_path); + fonts_path += "\\Fonts"; + pInfoFallback->AddPath(fonts_path); + } + return pInfoFallback; +} +void CFX_GEModule::InitPlatform() { + CWin32Platform* pPlatformData = new CWin32Platform; + OSVERSIONINFO ver; + ver.dwOSVersionInfoSize = sizeof(ver); + GetVersionEx(&ver); + pPlatformData->m_bHalfTone = ver.dwMajorVersion >= 5; + if (IsGDIEnabled()) { + pPlatformData->m_GdiplusExt.Load(); + } + m_pPlatformData = pPlatformData; + m_pFontMgr->SetSystemFontInfo(IFX_SystemFontInfo::CreateDefault(nullptr)); +} +void CFX_GEModule::DestroyPlatform() { + delete (CWin32Platform*)m_pPlatformData; + m_pPlatformData = NULL; +} +CGdiDeviceDriver::CGdiDeviceDriver(HDC hDC, int device_class) { + m_hDC = hDC; + m_DeviceClass = device_class; + CWin32Platform* pPlatform = + (CWin32Platform*)CFX_GEModule::Get()->GetPlatformData(); + SetStretchBltMode(hDC, pPlatform->m_bHalfTone ? HALFTONE : COLORONCOLOR); + if (GetObjectType(m_hDC) == OBJ_MEMDC) { + HBITMAP hBitmap = CreateBitmap(1, 1, 1, 1, NULL); + hBitmap = (HBITMAP)SelectObject(m_hDC, hBitmap); + BITMAP bitmap; + GetObject(hBitmap, sizeof bitmap, &bitmap); + m_nBitsPerPixel = bitmap.bmBitsPixel; + m_Width = bitmap.bmWidth; + m_Height = abs(bitmap.bmHeight); + hBitmap = (HBITMAP)SelectObject(m_hDC, hBitmap); + DeleteObject(hBitmap); + } else { + m_nBitsPerPixel = ::GetDeviceCaps(m_hDC, BITSPIXEL); + m_Width = ::GetDeviceCaps(m_hDC, HORZRES); + m_Height = ::GetDeviceCaps(m_hDC, VERTRES); + } + if (m_DeviceClass != FXDC_DISPLAY) { + m_RenderCaps = FXRC_BIT_MASK; + } else { + m_RenderCaps = FXRC_GET_BITS | FXRC_BIT_MASK; + } +} +int CGdiDeviceDriver::GetDeviceCaps(int caps_id) { + switch (caps_id) { + case FXDC_DEVICE_CLASS: + return m_DeviceClass; + case FXDC_PIXEL_WIDTH: + return m_Width; + case FXDC_PIXEL_HEIGHT: + return m_Height; + case FXDC_BITS_PIXEL: + return m_nBitsPerPixel; + case FXDC_RENDER_CAPS: + return m_RenderCaps; + } + return 0; +} +void* CGdiDeviceDriver::GetClipRgn() { + HRGN hClipRgn = CreateRectRgn(0, 0, 1, 1); + if (::GetClipRgn(m_hDC, hClipRgn) == 0) { + DeleteObject(hClipRgn); + hClipRgn = NULL; + } + return (void*)hClipRgn; +} +FX_BOOL CGdiDeviceDriver::GDI_SetDIBits(const CFX_DIBitmap* pBitmap1, + const FX_RECT* pSrcRect, + int left, + int top, + void* pIccTransform) { + if (m_DeviceClass == FXDC_PRINTER) { + CFX_DIBitmap* pBitmap = pBitmap1->FlipImage(FALSE, TRUE); + if (!pBitmap) { + return FALSE; + } + if ((pBitmap->IsCmykImage() || pIccTransform) && + !pBitmap->ConvertFormat(FXDIB_Rgb, pIccTransform)) { + return FALSE; + } + int width = pSrcRect->Width(), height = pSrcRect->Height(); + LPBYTE pBuffer = pBitmap->GetBuffer(); + CFX_ByteString info = CFX_WindowsDIB::GetBitmapInfo(pBitmap); + ((BITMAPINFOHEADER*)info.c_str())->biHeight *= -1; + FX_RECT dst_rect(0, 0, width, height); + dst_rect.Intersect(0, 0, pBitmap->GetWidth(), pBitmap->GetHeight()); + int dst_width = dst_rect.Width(); + int dst_height = dst_rect.Height(); + ::StretchDIBits(m_hDC, left, top, dst_width, dst_height, 0, 0, dst_width, + dst_height, pBuffer, (BITMAPINFO*)info.c_str(), + DIB_RGB_COLORS, SRCCOPY); + delete pBitmap; + } else { + CFX_DIBitmap* pBitmap = (CFX_DIBitmap*)pBitmap1; + if ((pBitmap->IsCmykImage() || pIccTransform) && + (pBitmap = pBitmap->CloneConvert(FXDIB_Rgb, NULL, pIccTransform)) == + NULL) { + return FALSE; + } + int width = pSrcRect->Width(), height = pSrcRect->Height(); + LPBYTE pBuffer = pBitmap->GetBuffer(); + CFX_ByteString info = CFX_WindowsDIB::GetBitmapInfo(pBitmap); + ::SetDIBitsToDevice(m_hDC, left, top, width, height, pSrcRect->left, + pBitmap->GetHeight() - pSrcRect->bottom, 0, + pBitmap->GetHeight(), pBuffer, + (BITMAPINFO*)info.c_str(), DIB_RGB_COLORS); + if (pBitmap != pBitmap1) { + delete pBitmap; + } + } + return TRUE; +} +FX_BOOL CGdiDeviceDriver::GDI_StretchDIBits(const CFX_DIBitmap* pBitmap1, + int dest_left, + int dest_top, + int dest_width, + int dest_height, + FX_DWORD flags, + void* pIccTransform) { + CFX_DIBitmap* pBitmap = (CFX_DIBitmap*)pBitmap1; + if (!pBitmap || dest_width == 0 || dest_height == 0) { + return FALSE; + } + if ((pBitmap->IsCmykImage() || pIccTransform) && + !pBitmap->ConvertFormat(FXDIB_Rgb, pIccTransform)) { + return FALSE; + } + CFX_ByteString info = CFX_WindowsDIB::GetBitmapInfo(pBitmap); + if ((int64_t)abs(dest_width) * abs(dest_height) < + (int64_t)pBitmap1->GetWidth() * pBitmap1->GetHeight() * 4 || + (flags & FXDIB_INTERPOL) || (flags & FXDIB_BICUBIC_INTERPOL)) { + SetStretchBltMode(m_hDC, HALFTONE); + } else { + SetStretchBltMode(m_hDC, COLORONCOLOR); + } + CFX_DIBitmap* pToStrechBitmap = pBitmap; + bool del = false; + if (m_DeviceClass == FXDC_PRINTER && + ((int64_t)pBitmap->GetWidth() * pBitmap->GetHeight() > + (int64_t)abs(dest_width) * abs(dest_height))) { + pToStrechBitmap = pBitmap->StretchTo(dest_width, dest_height); + del = true; + } + CFX_ByteString toStrechBitmapInfo = + CFX_WindowsDIB::GetBitmapInfo(pToStrechBitmap); + ::StretchDIBits(m_hDC, dest_left, dest_top, dest_width, dest_height, 0, 0, + pToStrechBitmap->GetWidth(), pToStrechBitmap->GetHeight(), + pToStrechBitmap->GetBuffer(), + (BITMAPINFO*)toStrechBitmapInfo.c_str(), DIB_RGB_COLORS, + SRCCOPY); + if (del) { + delete pToStrechBitmap; + } + return TRUE; +} +FX_BOOL CGdiDeviceDriver::GDI_StretchBitMask(const CFX_DIBitmap* pBitmap1, + int dest_left, + int dest_top, + int dest_width, + int dest_height, + FX_DWORD bitmap_color, + FX_DWORD flags, + int alpha_flag, + void* pIccTransform) { + CFX_DIBitmap* pBitmap = (CFX_DIBitmap*)pBitmap1; + if (!pBitmap || dest_width == 0 || dest_height == 0) { + return FALSE; + } + _Color2Argb(bitmap_color, bitmap_color, alpha_flag | (1 << 24), + pIccTransform); + int width = pBitmap->GetWidth(), height = pBitmap->GetHeight(); + struct { + BITMAPINFOHEADER bmiHeader; + FX_DWORD bmiColors[2]; + } bmi; + FXSYS_memset(&bmi.bmiHeader, 0, sizeof(BITMAPINFOHEADER)); + bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bmi.bmiHeader.biBitCount = 1; + bmi.bmiHeader.biCompression = BI_RGB; + bmi.bmiHeader.biHeight = -height; + bmi.bmiHeader.biPlanes = 1; + bmi.bmiHeader.biWidth = width; + if (m_nBitsPerPixel != 1) { + SetStretchBltMode(m_hDC, HALFTONE); + } + bmi.bmiColors[0] = 0xffffff; + bmi.bmiColors[1] = 0; + + HBRUSH hPattern = CreateSolidBrush(bitmap_color & 0xffffff); + HBRUSH hOld = (HBRUSH)SelectObject(m_hDC, hPattern); + + // In PDF, when image mask is 1, use device bitmap; when mask is 0, use brush + // bitmap. + // A complete list of the boolen operations is as follows: + + /* P(bitmap_color) S(ImageMask) D(DeviceBitmap) Result + * 0 0 0 0 + * 0 0 1 0 + * 0 1 0 0 + * 0 1 1 1 + * 1 0 0 1 + * 1 0 1 1 + * 1 1 0 0 + * 1 1 1 1 + */ + // The boolen codes is B8. Based on + // http://msdn.microsoft.com/en-us/library/aa932106.aspx, the ROP3 code is + // 0xB8074A + + ::StretchDIBits(m_hDC, dest_left, dest_top, dest_width, dest_height, 0, 0, + width, height, pBitmap->GetBuffer(), (BITMAPINFO*)&bmi, + DIB_RGB_COLORS, 0xB8074A); + + SelectObject(m_hDC, hOld); + DeleteObject(hPattern); + + return TRUE; +} +FX_BOOL CGdiDeviceDriver::GetClipBox(FX_RECT* pRect) { + return ::GetClipBox(m_hDC, (RECT*)pRect); +} +FX_BOOL CGdiDeviceDriver::SetClipRgn(void* hRgn) { + ::SelectClipRgn(m_hDC, (HRGN)hRgn); + return TRUE; +} +static HPEN _CreatePen(const CFX_GraphStateData* pGraphState, + const CFX_Matrix* pMatrix, + FX_DWORD argb) { + FX_FLOAT width; + FX_FLOAT scale = 1.f; + if (pMatrix) + scale = FXSYS_fabs(pMatrix->a) > FXSYS_fabs(pMatrix->b) + ? FXSYS_fabs(pMatrix->a) + : FXSYS_fabs(pMatrix->b); + if (pGraphState) { + width = scale * pGraphState->m_LineWidth; + } else { + width = 1.0f; + } + FX_DWORD PenStyle = PS_GEOMETRIC; + if (width < 1) { + width = 1; + } + if (pGraphState->m_DashCount) { + PenStyle |= PS_USERSTYLE; + } else { + PenStyle |= PS_SOLID; + } + switch (pGraphState->m_LineCap) { + case 0: + PenStyle |= PS_ENDCAP_FLAT; + break; + case 1: + PenStyle |= PS_ENDCAP_ROUND; + break; + case 2: + PenStyle |= PS_ENDCAP_SQUARE; + break; + } + switch (pGraphState->m_LineJoin) { + case 0: + PenStyle |= PS_JOIN_MITER; + break; + case 1: + PenStyle |= PS_JOIN_ROUND; + break; + case 2: + PenStyle |= PS_JOIN_BEVEL; + break; + } + int a; + FX_COLORREF rgb; + ArgbDecode(argb, a, rgb); + LOGBRUSH lb; + lb.lbColor = rgb; + lb.lbStyle = BS_SOLID; + lb.lbHatch = 0; + FX_DWORD* pDash = NULL; + if (pGraphState->m_DashCount) { + pDash = FX_Alloc(FX_DWORD, pGraphState->m_DashCount); + for (int i = 0; i < pGraphState->m_DashCount; i++) { + pDash[i] = FXSYS_round( + pMatrix ? pMatrix->TransformDistance(pGraphState->m_DashArray[i]) + : pGraphState->m_DashArray[i]); + if (pDash[i] < 1) { + pDash[i] = 1; + } + } + } + HPEN hPen = ExtCreatePen(PenStyle, (DWORD)FXSYS_ceil(width), &lb, + pGraphState->m_DashCount, (const DWORD*)pDash); + FX_Free(pDash); + return hPen; +} +static HBRUSH _CreateBrush(FX_DWORD argb) { + int a; + FX_COLORREF rgb; + ArgbDecode(argb, a, rgb); + return CreateSolidBrush(rgb); +} +static void _SetPathToDC(HDC hDC, + const CFX_PathData* pPathData, + const CFX_Matrix* pMatrix) { + BeginPath(hDC); + int nPoints = pPathData->GetPointCount(); + FX_PATHPOINT* pPoints = pPathData->GetPoints(); + for (int i = 0; i < nPoints; i++) { + FX_FLOAT posx = pPoints[i].m_PointX, posy = pPoints[i].m_PointY; + if (pMatrix) { + pMatrix->Transform(posx, posy); + } + int screen_x = FXSYS_round(posx), screen_y = FXSYS_round(posy); + int point_type = pPoints[i].m_Flag & FXPT_TYPE; + if (point_type == PT_MOVETO) { + MoveToEx(hDC, screen_x, screen_y, NULL); + } else if (point_type == PT_LINETO) { + if (pPoints[i].m_PointY == pPoints[i - 1].m_PointY && + pPoints[i].m_PointX == pPoints[i - 1].m_PointX) { + screen_x++; + } + LineTo(hDC, screen_x, screen_y); + } else if (point_type == PT_BEZIERTO) { + POINT lppt[3]; + lppt[0].x = screen_x; + lppt[0].y = screen_y; + posx = pPoints[i + 1].m_PointX; + posy = pPoints[i + 1].m_PointY; + if (pMatrix) { + pMatrix->Transform(posx, posy); + } + lppt[1].x = FXSYS_round(posx); + lppt[1].y = FXSYS_round(posy); + posx = pPoints[i + 2].m_PointX; + posy = pPoints[i + 2].m_PointY; + if (pMatrix) { + pMatrix->Transform(posx, posy); + } + lppt[2].x = FXSYS_round(posx); + lppt[2].y = FXSYS_round(posy); + PolyBezierTo(hDC, lppt, 3); + i += 2; + } + if (pPoints[i].m_Flag & PT_CLOSEFIGURE) { + CloseFigure(hDC); + } + } + EndPath(hDC); +} +void CGdiDeviceDriver::DrawLine(FX_FLOAT x1, + FX_FLOAT y1, + FX_FLOAT x2, + FX_FLOAT y2) { + int flag1 = (x1 < 0) | ((x1 > m_Width) << 1) | ((y1 < 0) << 2) | + ((y1 > m_Height) << 3); + int flag2 = (x2 < 0) | ((x2 > m_Width) << 1) | ((y2 < 0) << 2) | + ((y2 > m_Height) << 3); + if (flag1 & flag2) { + return; + } + if (flag1 || flag2) { + agg::rect_base<FX_FLOAT> rect(0.0f, 0.0f, (FX_FLOAT)(m_Width), + (FX_FLOAT)(m_Height)); + FX_FLOAT x[2], y[2]; + int np = agg::clip_liang_barsky<FX_FLOAT>(x1, y1, x2, y2, rect, x, y); + if (np == 0) { + return; + } + if (np == 1) { + x2 = x[0]; + y2 = y[0]; + } else { + x1 = x[0]; + y1 = y[0]; + x2 = x[np - 1]; + y2 = y[np - 1]; + } + } + MoveToEx(m_hDC, FXSYS_round(x1), FXSYS_round(y1), NULL); + LineTo(m_hDC, FXSYS_round(x2), FXSYS_round(y2)); +} +static FX_BOOL _MatrixNoScaled(const CFX_Matrix* pMatrix) { + return pMatrix->GetA() == 1.0f && pMatrix->GetB() == 0 && + pMatrix->GetC() == 0 && pMatrix->GetD() == 1.0f; +} +FX_BOOL CGdiDeviceDriver::DrawPath(const CFX_PathData* pPathData, + const CFX_Matrix* pMatrix, + const CFX_GraphStateData* pGraphState, + FX_DWORD fill_color, + FX_DWORD stroke_color, + int fill_mode, + int alpha_flag, + void* pIccTransform, + int blend_type) { + if (blend_type != FXDIB_BLEND_NORMAL) { + return FALSE; + } + _Color2Argb(fill_color, fill_color, alpha_flag | (1 << 24), pIccTransform); + _Color2Argb(stroke_color, stroke_color, alpha_flag, pIccTransform); + CWin32Platform* pPlatform = + (CWin32Platform*)CFX_GEModule::Get()->GetPlatformData(); + if (!(pGraphState || stroke_color == 0) && + !pPlatform->m_GdiplusExt.IsAvailable()) { + CFX_FloatRect bbox_f = pPathData->GetBoundingBox(); + if (pMatrix) { + bbox_f.Transform(pMatrix); + } + FX_RECT bbox = bbox_f.GetInnerRect(); + if (bbox.Width() <= 0) { + return DrawCosmeticLine((FX_FLOAT)(bbox.left), (FX_FLOAT)(bbox.top), + (FX_FLOAT)(bbox.left), + (FX_FLOAT)(bbox.bottom + 1), fill_color, + alpha_flag, pIccTransform, FXDIB_BLEND_NORMAL); + } else if (bbox.Height() <= 0) { + return DrawCosmeticLine((FX_FLOAT)(bbox.left), (FX_FLOAT)(bbox.top), + (FX_FLOAT)(bbox.right + 1), (FX_FLOAT)(bbox.top), + fill_color, alpha_flag, pIccTransform, + FXDIB_BLEND_NORMAL); + } + } + int fill_alpha = FXARGB_A(fill_color); + int stroke_alpha = FXARGB_A(stroke_color); + FX_BOOL bDrawAlpha = (fill_alpha > 0 && fill_alpha < 255) || + (stroke_alpha > 0 && stroke_alpha < 255 && pGraphState); + if (!pPlatform->m_GdiplusExt.IsAvailable() && bDrawAlpha) { + return FALSE; + } + if (pPlatform->m_GdiplusExt.IsAvailable()) { + if (bDrawAlpha || + ((m_DeviceClass != FXDC_PRINTER && !(fill_mode & FXFILL_FULLCOVER)) || + (pGraphState && pGraphState->m_DashCount))) { + if (!((NULL == pMatrix || _MatrixNoScaled(pMatrix)) && pGraphState && + pGraphState->m_LineWidth == 1.f && + (pPathData->GetPointCount() == 5 || + pPathData->GetPointCount() == 4) && + pPathData->IsRect())) { + if (pPlatform->m_GdiplusExt.DrawPath(m_hDC, pPathData, pMatrix, + pGraphState, fill_color, + stroke_color, fill_mode)) { + return TRUE; + } + } + } + } + int old_fill_mode = fill_mode; + fill_mode &= 3; + HPEN hPen = NULL; + HBRUSH hBrush = NULL; + if (pGraphState && stroke_alpha) { + SetMiterLimit(m_hDC, pGraphState->m_MiterLimit, NULL); + hPen = _CreatePen(pGraphState, pMatrix, stroke_color); + hPen = (HPEN)SelectObject(m_hDC, hPen); + } + if (fill_mode && fill_alpha) { + SetPolyFillMode(m_hDC, fill_mode); + hBrush = _CreateBrush(fill_color); + hBrush = (HBRUSH)SelectObject(m_hDC, hBrush); + } + if (pPathData->GetPointCount() == 2 && pGraphState && + pGraphState->m_DashCount) { + FX_FLOAT x1 = pPathData->GetPointX(0), y1 = pPathData->GetPointY(0); + if (pMatrix) { + pMatrix->Transform(x1, y1); + } + FX_FLOAT x2 = pPathData->GetPointX(1), y2 = pPathData->GetPointY(1); + if (pMatrix) { + pMatrix->Transform(x2, y2); + } + DrawLine(x1, y1, x2, y2); + } else { + _SetPathToDC(m_hDC, pPathData, pMatrix); + if (pGraphState && stroke_alpha) { + if (fill_mode && fill_alpha) { + if (old_fill_mode & FX_FILL_TEXT_MODE) { + StrokeAndFillPath(m_hDC); + } else { + FillPath(m_hDC); + _SetPathToDC(m_hDC, pPathData, pMatrix); + StrokePath(m_hDC); + } + } else { + StrokePath(m_hDC); + } + } else if (fill_mode && fill_alpha) { + FillPath(m_hDC); + } + } + if (hPen) { + hPen = (HPEN)SelectObject(m_hDC, hPen); + DeleteObject(hPen); + } + if (hBrush) { + hBrush = (HBRUSH)SelectObject(m_hDC, hBrush); + DeleteObject(hBrush); + } + return TRUE; +} +FX_BOOL CGdiDeviceDriver::FillRect(const FX_RECT* pRect, + FX_DWORD fill_color, + int alpha_flag, + void* pIccTransform, + int blend_type) { + if (blend_type != FXDIB_BLEND_NORMAL) { + return FALSE; + } + _Color2Argb(fill_color, fill_color, alpha_flag | (1 << 24), pIccTransform); + int alpha; + FX_COLORREF rgb; + ArgbDecode(fill_color, alpha, rgb); + if (alpha == 0) { + return TRUE; + } + if (alpha < 255) { + return FALSE; + } + HBRUSH hBrush = CreateSolidBrush(rgb); + ::FillRect(m_hDC, (RECT*)pRect, hBrush); + DeleteObject(hBrush); + return TRUE; +} +FX_BOOL CGdiDeviceDriver::SetClip_PathFill(const CFX_PathData* pPathData, + const CFX_Matrix* pMatrix, + int fill_mode) { + if (pPathData->GetPointCount() == 5) { + CFX_FloatRect rectf; + if (pPathData->IsRect(pMatrix, &rectf)) { + FX_RECT rect = rectf.GetOutterRect(); + IntersectClipRect(m_hDC, rect.left, rect.top, rect.right, rect.bottom); + return TRUE; + } + } + _SetPathToDC(m_hDC, pPathData, pMatrix); + SetPolyFillMode(m_hDC, fill_mode & 3); + SelectClipPath(m_hDC, RGN_AND); + return TRUE; +} +FX_BOOL CGdiDeviceDriver::SetClip_PathStroke( + const CFX_PathData* pPathData, + const CFX_Matrix* pMatrix, + const CFX_GraphStateData* pGraphState) { + HPEN hPen = _CreatePen(pGraphState, pMatrix, 0xff000000); + hPen = (HPEN)SelectObject(m_hDC, hPen); + _SetPathToDC(m_hDC, pPathData, pMatrix); + WidenPath(m_hDC); + SetPolyFillMode(m_hDC, WINDING); + FX_BOOL ret = SelectClipPath(m_hDC, RGN_AND); + hPen = (HPEN)SelectObject(m_hDC, hPen); + DeleteObject(hPen); + return ret; +} +FX_BOOL CGdiDeviceDriver::DrawCosmeticLine(FX_FLOAT x1, + FX_FLOAT y1, + FX_FLOAT x2, + FX_FLOAT y2, + FX_DWORD color, + int alpha_flag, + void* pIccTransform, + int blend_type) { + if (blend_type != FXDIB_BLEND_NORMAL) { + return FALSE; + } + _Color2Argb(color, color, alpha_flag | (1 << 24), pIccTransform); + int a; + FX_COLORREF rgb; + ArgbDecode(color, a, rgb); + if (a == 0) { + return TRUE; + } + HPEN hPen = CreatePen(PS_SOLID, 1, rgb); + hPen = (HPEN)SelectObject(m_hDC, hPen); + MoveToEx(m_hDC, FXSYS_round(x1), FXSYS_round(y1), NULL); + LineTo(m_hDC, FXSYS_round(x2), FXSYS_round(y2)); + hPen = (HPEN)SelectObject(m_hDC, hPen); + DeleteObject(hPen); + return TRUE; +} +FX_BOOL CGdiDeviceDriver::DeleteDeviceRgn(void* pRgn) { + DeleteObject((HGDIOBJ)pRgn); + return TRUE; +} +CGdiDisplayDriver::CGdiDisplayDriver(HDC hDC) + : CGdiDeviceDriver(hDC, FXDC_DISPLAY) { + CWin32Platform* pPlatform = + (CWin32Platform*)CFX_GEModule::Get()->GetPlatformData(); + if (pPlatform->m_GdiplusExt.IsAvailable()) { + m_RenderCaps |= FXRC_ALPHA_PATH | FXRC_ALPHA_IMAGE; + } +} +FX_BOOL CGdiDisplayDriver::GetDIBits(CFX_DIBitmap* pBitmap, + int left, + int top, + void* pIccTransform, + FX_BOOL bDEdge) { + FX_BOOL ret = FALSE; + int width = pBitmap->GetWidth(); + int height = pBitmap->GetHeight(); + HBITMAP hbmp = CreateCompatibleBitmap(m_hDC, width, height); + HDC hDCMemory = CreateCompatibleDC(m_hDC); + HBITMAP holdbmp = (HBITMAP)SelectObject(hDCMemory, hbmp); + BitBlt(hDCMemory, 0, 0, width, height, m_hDC, left, top, SRCCOPY); + SelectObject(hDCMemory, holdbmp); + BITMAPINFO bmi; + FXSYS_memset(&bmi, 0, sizeof bmi); + bmi.bmiHeader.biSize = sizeof bmi.bmiHeader; + bmi.bmiHeader.biBitCount = pBitmap->GetBPP(); + bmi.bmiHeader.biHeight = -height; + bmi.bmiHeader.biPlanes = 1; + bmi.bmiHeader.biWidth = width; + if (!CFX_GEModule::Get()->GetCodecModule() || + !CFX_GEModule::Get()->GetCodecModule()->GetIccModule()) { + pIccTransform = NULL; + } + if (pBitmap->GetBPP() > 8 && !pBitmap->IsCmykImage() && !pIccTransform) { + ret = ::GetDIBits(hDCMemory, hbmp, 0, height, pBitmap->GetBuffer(), &bmi, + DIB_RGB_COLORS) == height; + } else { + CFX_DIBitmap bitmap; + if (bitmap.Create(width, height, FXDIB_Rgb)) { + bmi.bmiHeader.biBitCount = 24; + ::GetDIBits(hDCMemory, hbmp, 0, height, bitmap.GetBuffer(), &bmi, + DIB_RGB_COLORS); + ret = pBitmap->TransferBitmap(0, 0, width, height, &bitmap, 0, 0, + pIccTransform); + } else { + ret = FALSE; + } + } + if (pBitmap->HasAlpha() && ret) { + pBitmap->LoadChannel(FXDIB_Alpha, 0xff); + } + DeleteObject(hbmp); + DeleteObject(hDCMemory); + return ret; +} +FX_BOOL CGdiDisplayDriver::SetDIBits(const CFX_DIBSource* pSource, + FX_DWORD color, + const FX_RECT* pSrcRect, + int left, + int top, + int blend_type, + int alpha_flag, + void* pIccTransform) { + ASSERT(blend_type == FXDIB_BLEND_NORMAL); + if (pSource->IsAlphaMask()) { + int width = pSource->GetWidth(), height = pSource->GetHeight(); + int alpha = FXGETFLAG_COLORTYPE(alpha_flag) + ? FXGETFLAG_ALPHA_FILL(alpha_flag) + : FXARGB_A(color); + if (pSource->GetBPP() != 1 || alpha != 255) { + CFX_DIBitmap background; + if (!background.Create(width, height, FXDIB_Rgb32) || + !GetDIBits(&background, left, top, NULL) || + !background.CompositeMask(0, 0, width, height, pSource, color, 0, 0, + FXDIB_BLEND_NORMAL, NULL, FALSE, alpha_flag, + pIccTransform)) { + return FALSE; + } + FX_RECT src_rect(0, 0, width, height); + return SetDIBits(&background, 0, &src_rect, left, top, FXDIB_BLEND_NORMAL, + 0, NULL); + } + FX_RECT clip_rect(left, top, left + pSrcRect->Width(), + top + pSrcRect->Height()); + return StretchDIBits(pSource, color, left - pSrcRect->left, + top - pSrcRect->top, width, height, &clip_rect, 0, + alpha_flag, pIccTransform, FXDIB_BLEND_NORMAL); + } + int width = pSrcRect->Width(), height = pSrcRect->Height(); + if (pSource->HasAlpha()) { + CFX_DIBitmap bitmap; + if (!bitmap.Create(width, height, FXDIB_Rgb) || + !GetDIBits(&bitmap, left, top, NULL) || + !bitmap.CompositeBitmap(0, 0, width, height, pSource, pSrcRect->left, + pSrcRect->top, FXDIB_BLEND_NORMAL, NULL, FALSE, + pIccTransform)) { + return FALSE; + } + FX_RECT src_rect(0, 0, width, height); + return SetDIBits(&bitmap, 0, &src_rect, left, top, FXDIB_BLEND_NORMAL, 0, + NULL); + } + CFX_DIBExtractor temp(pSource); + CFX_DIBitmap* pBitmap = temp; + if (pBitmap) { + return GDI_SetDIBits(pBitmap, pSrcRect, left, top, pIccTransform); + } + return FALSE; +} +FX_BOOL CGdiDisplayDriver::UseFoxitStretchEngine(const CFX_DIBSource* pSource, + FX_DWORD color, + int dest_left, + int dest_top, + int dest_width, + int dest_height, + const FX_RECT* pClipRect, + int render_flags, + int alpha_flag, + void* pIccTransform, + int blend_type) { + FX_RECT bitmap_clip = *pClipRect; + if (dest_width < 0) { + dest_left += dest_width; + } + if (dest_height < 0) { + dest_top += dest_height; + } + bitmap_clip.Offset(-dest_left, -dest_top); + CFX_DIBitmap* pStretched = + pSource->StretchTo(dest_width, dest_height, render_flags, &bitmap_clip); + if (!pStretched) { + return TRUE; + } + FX_RECT src_rect(0, 0, pStretched->GetWidth(), pStretched->GetHeight()); + FX_BOOL ret = + SetDIBits(pStretched, color, &src_rect, pClipRect->left, pClipRect->top, + FXDIB_BLEND_NORMAL, alpha_flag, pIccTransform); + delete pStretched; + return ret; +} +FX_BOOL CGdiDisplayDriver::StretchDIBits(const CFX_DIBSource* pSource, + FX_DWORD color, + int dest_left, + int dest_top, + int dest_width, + int dest_height, + const FX_RECT* pClipRect, + FX_DWORD flags, + int alpha_flag, + void* pIccTransform, + int blend_type) { + ASSERT(pSource && pClipRect); + if (flags || dest_width > 10000 || dest_width < -10000 || + dest_height > 10000 || dest_height < -10000) { + return UseFoxitStretchEngine(pSource, color, dest_left, dest_top, + dest_width, dest_height, pClipRect, flags, + alpha_flag, pIccTransform, blend_type); + } + if (pSource->IsAlphaMask()) { + FX_RECT image_rect; + image_rect.left = dest_width > 0 ? dest_left : dest_left + dest_width; + image_rect.right = dest_width > 0 ? dest_left + dest_width : dest_left; + image_rect.top = dest_height > 0 ? dest_top : dest_top + dest_height; + image_rect.bottom = dest_height > 0 ? dest_top + dest_height : dest_top; + FX_RECT clip_rect = image_rect; + clip_rect.Intersect(*pClipRect); + clip_rect.Offset(-image_rect.left, -image_rect.top); + int clip_width = clip_rect.Width(), clip_height = clip_rect.Height(); + CFX_DIBitmap* pStretched = + pSource->StretchTo(dest_width, dest_height, flags, &clip_rect); + if (!pStretched) { + return TRUE; + } + CFX_DIBitmap background; + if (!background.Create(clip_width, clip_height, FXDIB_Rgb32) || + !GetDIBits(&background, image_rect.left + clip_rect.left, + image_rect.top + clip_rect.top, NULL) || + !background.CompositeMask(0, 0, clip_width, clip_height, pStretched, + color, 0, 0, FXDIB_BLEND_NORMAL, NULL, FALSE, + alpha_flag, pIccTransform)) { + delete pStretched; + return FALSE; + } + FX_RECT src_rect(0, 0, clip_width, clip_height); + FX_BOOL ret = + SetDIBits(&background, 0, &src_rect, image_rect.left + clip_rect.left, + image_rect.top + clip_rect.top, FXDIB_BLEND_NORMAL, 0, NULL); + delete pStretched; + return ret; + } + if (pSource->HasAlpha()) { + CWin32Platform* pPlatform = + (CWin32Platform*)CFX_GEModule::Get()->GetPlatformData(); + if (pPlatform->m_GdiplusExt.IsAvailable() && !pIccTransform && + !pSource->IsCmykImage()) { + CFX_DIBExtractor temp(pSource); + CFX_DIBitmap* pBitmap = temp; + if (!pBitmap) { + return FALSE; + } + return pPlatform->m_GdiplusExt.StretchDIBits( + m_hDC, pBitmap, dest_left, dest_top, dest_width, dest_height, + pClipRect, flags); + } + return UseFoxitStretchEngine(pSource, color, dest_left, dest_top, + dest_width, dest_height, pClipRect, flags, + alpha_flag, pIccTransform, blend_type); + } + CFX_DIBExtractor temp(pSource); + CFX_DIBitmap* pBitmap = temp; + if (pBitmap) { + return GDI_StretchDIBits(pBitmap, dest_left, dest_top, dest_width, + dest_height, flags, pIccTransform); + } + return FALSE; +} +#define GET_PS_FEATURESETTING 4121 +#define FEATURESETTING_PSLEVEL 2 +int GetPSLevel(HDC hDC) { + int device_type = ::GetDeviceCaps(hDC, TECHNOLOGY); + if (device_type != DT_RASPRINTER) { + return 0; + } + FX_DWORD esc = GET_PS_FEATURESETTING; + if (ExtEscape(hDC, QUERYESCSUPPORT, sizeof esc, (char*)&esc, 0, NULL)) { + int param = FEATURESETTING_PSLEVEL; + if (ExtEscape(hDC, GET_PS_FEATURESETTING, sizeof(int), (char*)¶m, + sizeof(int), (char*)¶m) > 0) { + return param; + } + } + esc = POSTSCRIPT_IDENTIFY; + if (ExtEscape(hDC, QUERYESCSUPPORT, sizeof esc, (char*)&esc, 0, NULL) == 0) { + esc = POSTSCRIPT_DATA; + if (ExtEscape(hDC, QUERYESCSUPPORT, sizeof esc, (char*)&esc, 0, NULL)) { + return 2; + } + return 0; + } + esc = PSIDENT_GDICENTRIC; + if (ExtEscape(hDC, POSTSCRIPT_IDENTIFY, sizeof(FX_DWORD), (char*)&esc, 0, + NULL) <= 0) { + return 2; + } + esc = GET_PS_FEATURESETTING; + if (ExtEscape(hDC, QUERYESCSUPPORT, sizeof esc, (char*)&esc, 0, NULL)) { + int param = FEATURESETTING_PSLEVEL; + if (ExtEscape(hDC, GET_PS_FEATURESETTING, sizeof(int), (char*)¶m, + sizeof(int), (char*)¶m) > 0) { + return param; + } + } + return 2; +} +int CFX_WindowsDevice::m_psLevel = 2; +CFX_WindowsDevice::CFX_WindowsDevice(HDC hDC, + FX_BOOL bCmykOutput, + FX_BOOL bForcePSOutput, + int psLevel) { + m_bForcePSOutput = bForcePSOutput; + m_psLevel = psLevel; + if (bForcePSOutput) { + IFX_RenderDeviceDriver* pDriver = new CPSPrinterDriver; + ((CPSPrinterDriver*)pDriver)->Init(hDC, psLevel, bCmykOutput); + SetDeviceDriver(pDriver); + return; + } + SetDeviceDriver(CreateDriver(hDC, bCmykOutput)); +} +HDC CFX_WindowsDevice::GetDC() const { + IFX_RenderDeviceDriver* pRDD = GetDeviceDriver(); + if (!pRDD) { + return NULL; + } + return (HDC)pRDD->GetPlatformSurface(); +} +IFX_RenderDeviceDriver* CFX_WindowsDevice::CreateDriver(HDC hDC, + FX_BOOL bCmykOutput) { + int device_type = ::GetDeviceCaps(hDC, TECHNOLOGY); + int obj_type = ::GetObjectType(hDC); + int device_class; + if (device_type == DT_RASPRINTER || device_type == DT_PLOTTER || + obj_type == OBJ_ENHMETADC) { + device_class = FXDC_PRINTER; + } else { + device_class = FXDC_DISPLAY; + } + if (device_class == FXDC_PRINTER) { + return new CGdiPrinterDriver(hDC); + } + return new CGdiDisplayDriver(hDC); +} +CFX_WinBitmapDevice::CFX_WinBitmapDevice(int width, + int height, + FXDIB_Format format) { + BITMAPINFOHEADER bmih; + FXSYS_memset(&bmih, 0, sizeof(BITMAPINFOHEADER)); + bmih.biSize = sizeof(BITMAPINFOHEADER); + bmih.biBitCount = format & 0xff; + bmih.biHeight = -height; + bmih.biPlanes = 1; + bmih.biWidth = width; + uint8_t* pBuffer; + m_hBitmap = CreateDIBSection(NULL, (BITMAPINFO*)&bmih, DIB_RGB_COLORS, + (void**)&pBuffer, NULL, 0); + if (!m_hBitmap) { + return; + } + CFX_DIBitmap* pBitmap = new CFX_DIBitmap; + pBitmap->Create(width, height, format, pBuffer); + SetBitmap(pBitmap); + m_hDC = ::CreateCompatibleDC(NULL); + m_hOldBitmap = (HBITMAP)SelectObject(m_hDC, m_hBitmap); + IFX_RenderDeviceDriver* pDriver = new CGdiDisplayDriver(m_hDC); + SetDeviceDriver(pDriver); +} +CFX_WinBitmapDevice::~CFX_WinBitmapDevice() { + if (m_hDC) { + SelectObject(m_hDC, m_hOldBitmap); + DeleteDC(m_hDC); + } + if (m_hBitmap) { + DeleteObject(m_hBitmap); + } + delete GetBitmap(); +} + +#endif // _FX_OS_ == _FX_WIN32_DESKTOP_ || _FX_OS_ == _FX_WIN64_ diff --git a/core/fxge/win32/fx_win32_dib.cpp b/core/fxge/win32/fx_win32_dib.cpp new file mode 100644 index 0000000000..cd48d07554 --- /dev/null +++ b/core/fxge/win32/fx_win32_dib.cpp @@ -0,0 +1,289 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "core/include/fxge/fx_ge.h" + +#if _FX_OS_ == _FX_WIN32_DESKTOP_ || _FX_OS_ == _FX_WIN64_DESKTOP_ +#include <windows.h> + +#include "core/fxge/win32/win32_int.h" +#include "core/include/fxge/fx_ge_win32.h" + +CFX_ByteString CFX_WindowsDIB::GetBitmapInfo(const CFX_DIBitmap* pBitmap) { + CFX_ByteString result; + int len = sizeof(BITMAPINFOHEADER); + if (pBitmap->GetBPP() == 1 || pBitmap->GetBPP() == 8) { + len += sizeof(DWORD) * (int)(1 << pBitmap->GetBPP()); + } + BITMAPINFOHEADER* pbmih = (BITMAPINFOHEADER*)result.GetBuffer(len); + FXSYS_memset(pbmih, 0, sizeof(BITMAPINFOHEADER)); + pbmih->biSize = sizeof(BITMAPINFOHEADER); + pbmih->biBitCount = pBitmap->GetBPP(); + pbmih->biCompression = BI_RGB; + pbmih->biHeight = -(int)pBitmap->GetHeight(); + pbmih->biPlanes = 1; + pbmih->biWidth = pBitmap->GetWidth(); + if (pBitmap->GetBPP() == 8) { + FX_DWORD* pPalette = (FX_DWORD*)(pbmih + 1); + if (pBitmap->GetPalette()) { + for (int i = 0; i < 256; i++) { + pPalette[i] = pBitmap->GetPalette()[i]; + } + } else { + for (int i = 0; i < 256; i++) { + pPalette[i] = i * 0x010101; + } + } + } + if (pBitmap->GetBPP() == 1) { + FX_DWORD* pPalette = (FX_DWORD*)(pbmih + 1); + if (pBitmap->GetPalette()) { + pPalette[0] = pBitmap->GetPalette()[0]; + pPalette[1] = pBitmap->GetPalette()[1]; + } else { + pPalette[0] = 0; + pPalette[1] = 0xffffff; + } + } + result.ReleaseBuffer(len); + return result; +} +CFX_DIBitmap* _FX_WindowsDIB_LoadFromBuf(BITMAPINFO* pbmi, + LPVOID pData, + FX_BOOL bAlpha) { + int width = pbmi->bmiHeader.biWidth; + int height = pbmi->bmiHeader.biHeight; + BOOL bBottomUp = TRUE; + if (height < 0) { + height = -height; + bBottomUp = FALSE; + } + int pitch = (width * pbmi->bmiHeader.biBitCount + 31) / 32 * 4; + CFX_DIBitmap* pBitmap = new CFX_DIBitmap; + FXDIB_Format format = bAlpha + ? (FXDIB_Format)(pbmi->bmiHeader.biBitCount + 0x200) + : (FXDIB_Format)pbmi->bmiHeader.biBitCount; + FX_BOOL ret = pBitmap->Create(width, height, format); + if (!ret) { + delete pBitmap; + return NULL; + } + FXSYS_memcpy(pBitmap->GetBuffer(), pData, pitch * height); + if (bBottomUp) { + uint8_t* temp_buf = FX_Alloc(uint8_t, pitch); + int top = 0, bottom = height - 1; + while (top < bottom) { + FXSYS_memcpy(temp_buf, pBitmap->GetBuffer() + top * pitch, pitch); + FXSYS_memcpy(pBitmap->GetBuffer() + top * pitch, + pBitmap->GetBuffer() + bottom * pitch, pitch); + FXSYS_memcpy(pBitmap->GetBuffer() + bottom * pitch, temp_buf, pitch); + top++; + bottom--; + } + FX_Free(temp_buf); + temp_buf = NULL; + } + if (pbmi->bmiHeader.biBitCount == 1) { + for (int i = 0; i < 2; i++) { + pBitmap->SetPaletteEntry(i, ((FX_DWORD*)pbmi->bmiColors)[i] | 0xff000000); + } + } else if (pbmi->bmiHeader.biBitCount == 8) { + for (int i = 0; i < 256; i++) { + pBitmap->SetPaletteEntry(i, ((FX_DWORD*)pbmi->bmiColors)[i] | 0xff000000); + } + } + return pBitmap; +} +CFX_DIBitmap* CFX_WindowsDIB::LoadFromBuf(BITMAPINFO* pbmi, LPVOID pData) { + return _FX_WindowsDIB_LoadFromBuf(pbmi, pData, FALSE); +} +HBITMAP CFX_WindowsDIB::GetDDBitmap(const CFX_DIBitmap* pBitmap, HDC hDC) { + CFX_ByteString info = GetBitmapInfo(pBitmap); + HBITMAP hBitmap = NULL; + hBitmap = CreateDIBitmap(hDC, (BITMAPINFOHEADER*)info.c_str(), CBM_INIT, + pBitmap->GetBuffer(), (BITMAPINFO*)info.c_str(), + DIB_RGB_COLORS); + return hBitmap; +} +void GetBitmapSize(HBITMAP hBitmap, int& w, int& h) { + BITMAP bmp; + GetObject(hBitmap, sizeof bmp, &bmp); + w = bmp.bmWidth; + h = bmp.bmHeight; +} +CFX_DIBitmap* CFX_WindowsDIB::LoadFromFile(const FX_WCHAR* filename) { + CWin32Platform* pPlatform = + (CWin32Platform*)CFX_GEModule::Get()->GetPlatformData(); + if (pPlatform->m_GdiplusExt.IsAvailable()) { + WINDIB_Open_Args_ args; + args.flags = WINDIB_OPEN_PATHNAME; + args.path_name = filename; + return pPlatform->m_GdiplusExt.LoadDIBitmap(args); + } + HBITMAP hBitmap = (HBITMAP)LoadImageW(NULL, (wchar_t*)filename, IMAGE_BITMAP, + 0, 0, LR_LOADFROMFILE); + if (!hBitmap) { + return NULL; + } + HDC hDC = CreateCompatibleDC(NULL); + int width, height; + GetBitmapSize(hBitmap, width, height); + CFX_DIBitmap* pDIBitmap = new CFX_DIBitmap; + if (!pDIBitmap->Create(width, height, FXDIB_Rgb)) { + delete pDIBitmap; + DeleteDC(hDC); + return NULL; + } + CFX_ByteString info = GetBitmapInfo(pDIBitmap); + int ret = GetDIBits(hDC, hBitmap, 0, height, pDIBitmap->GetBuffer(), + (BITMAPINFO*)info.c_str(), DIB_RGB_COLORS); + if (!ret) { + delete pDIBitmap; + pDIBitmap = NULL; + } + DeleteDC(hDC); + return pDIBitmap; +} +CFX_DIBitmap* CFX_WindowsDIB::LoadDIBitmap(WINDIB_Open_Args_ args) { + CWin32Platform* pPlatform = + (CWin32Platform*)CFX_GEModule::Get()->GetPlatformData(); + if (pPlatform->m_GdiplusExt.IsAvailable()) { + return pPlatform->m_GdiplusExt.LoadDIBitmap(args); + } + if (args.flags == WINDIB_OPEN_MEMORY) { + return NULL; + } + HBITMAP hBitmap = (HBITMAP)LoadImageW(NULL, (wchar_t*)args.path_name, + IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE); + if (!hBitmap) { + return NULL; + } + HDC hDC = CreateCompatibleDC(NULL); + int width, height; + GetBitmapSize(hBitmap, width, height); + CFX_DIBitmap* pDIBitmap = new CFX_DIBitmap; + if (!pDIBitmap->Create(width, height, FXDIB_Rgb)) { + delete pDIBitmap; + DeleteDC(hDC); + return NULL; + } + CFX_ByteString info = GetBitmapInfo(pDIBitmap); + int ret = GetDIBits(hDC, hBitmap, 0, height, pDIBitmap->GetBuffer(), + (BITMAPINFO*)info.c_str(), DIB_RGB_COLORS); + if (!ret) { + delete pDIBitmap; + pDIBitmap = NULL; + } + DeleteDC(hDC); + return pDIBitmap; +} +CFX_DIBitmap* CFX_WindowsDIB::LoadFromDDB(HDC hDC, + HBITMAP hBitmap, + FX_DWORD* pPalette, + FX_DWORD palsize) { + FX_BOOL bCreatedDC = !hDC; + if (bCreatedDC) { + hDC = CreateCompatibleDC(NULL); + } + BITMAPINFOHEADER bmih; + FXSYS_memset(&bmih, 0, sizeof bmih); + bmih.biSize = sizeof bmih; + GetDIBits(hDC, hBitmap, 0, 0, NULL, (BITMAPINFO*)&bmih, DIB_RGB_COLORS); + int width = bmih.biWidth; + int height = abs(bmih.biHeight); + bmih.biHeight = -height; + bmih.biCompression = BI_RGB; + CFX_DIBitmap* pDIBitmap = new CFX_DIBitmap; + int ret = 0; + if (bmih.biBitCount == 1 || bmih.biBitCount == 8) { + int size = sizeof(BITMAPINFOHEADER) + 8; + if (bmih.biBitCount == 8) { + size += sizeof(FX_DWORD) * 254; + } + BITMAPINFO* pbmih = (BITMAPINFO*)FX_Alloc(uint8_t, size); + pbmih->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + pbmih->bmiHeader.biBitCount = bmih.biBitCount; + pbmih->bmiHeader.biCompression = BI_RGB; + pbmih->bmiHeader.biHeight = -height; + pbmih->bmiHeader.biPlanes = 1; + pbmih->bmiHeader.biWidth = bmih.biWidth; + if (!pDIBitmap->Create(bmih.biWidth, height, bmih.biBitCount == 1 + ? FXDIB_1bppRgb + : FXDIB_8bppRgb)) { + delete pDIBitmap; + FX_Free(pbmih); + if (bCreatedDC) { + DeleteDC(hDC); + } + return NULL; + } + ret = GetDIBits(hDC, hBitmap, 0, height, pDIBitmap->GetBuffer(), + (BITMAPINFO*)pbmih, DIB_RGB_COLORS); + FX_Free(pbmih); + pbmih = NULL; + pDIBitmap->CopyPalette(pPalette, palsize); + } else { + if (bmih.biBitCount <= 24) { + bmih.biBitCount = 24; + } else { + bmih.biBitCount = 32; + } + if (!pDIBitmap->Create(bmih.biWidth, height, + bmih.biBitCount == 24 ? FXDIB_Rgb : FXDIB_Rgb32)) { + delete pDIBitmap; + if (bCreatedDC) { + DeleteDC(hDC); + } + return NULL; + } + ret = GetDIBits(hDC, hBitmap, 0, height, pDIBitmap->GetBuffer(), + (BITMAPINFO*)&bmih, DIB_RGB_COLORS); + if (ret != 0 && bmih.biBitCount == 32) { + int pitch = pDIBitmap->GetPitch(); + for (int row = 0; row < height; row++) { + uint8_t* dest_scan = (uint8_t*)(pDIBitmap->GetBuffer() + row * pitch); + for (int col = 0; col < width; col++) { + dest_scan[3] = 255; + dest_scan += 4; + } + } + } + } + if (ret == 0) { + delete pDIBitmap; + pDIBitmap = NULL; + } + if (bCreatedDC) { + DeleteDC(hDC); + } + return pDIBitmap; +} +CFX_WindowsDIB::CFX_WindowsDIB(HDC hDC, int width, int height) { + Create(width, height, FXDIB_Rgb, (uint8_t*)1); + BITMAPINFOHEADER bmih; + FXSYS_memset(&bmih, 0, sizeof bmih); + bmih.biSize = sizeof bmih; + bmih.biBitCount = 24; + bmih.biHeight = -height; + bmih.biPlanes = 1; + bmih.biWidth = width; + m_hBitmap = CreateDIBSection(hDC, (BITMAPINFO*)&bmih, DIB_RGB_COLORS, + (LPVOID*)&m_pBuffer, NULL, 0); + m_hMemDC = CreateCompatibleDC(hDC); + m_hOldBitmap = (HBITMAP)SelectObject(m_hMemDC, m_hBitmap); +} +CFX_WindowsDIB::~CFX_WindowsDIB() { + SelectObject(m_hMemDC, m_hOldBitmap); + DeleteDC(m_hMemDC); + DeleteObject(m_hBitmap); +} +void CFX_WindowsDIB::LoadFromDevice(HDC hDC, int left, int top) { + ::BitBlt(m_hMemDC, 0, 0, m_Width, m_Height, hDC, left, top, SRCCOPY); +} +void CFX_WindowsDIB::SetToDevice(HDC hDC, int left, int top) { + ::BitBlt(hDC, left, top, m_Width, m_Height, m_hMemDC, 0, 0, SRCCOPY); +} +#endif diff --git a/core/fxge/win32/fx_win32_dwrite.cpp b/core/fxge/win32/fx_win32_dwrite.cpp new file mode 100644 index 0000000000..972295c5cc --- /dev/null +++ b/core/fxge/win32/fx_win32_dwrite.cpp @@ -0,0 +1,410 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "core/include/fxge/fx_ge.h" + +#if _FX_OS_ == _FX_WIN32_DESKTOP_ || _FX_OS_ == _FX_WIN64_DESKTOP_ +#include <dwrite.h> + +#include "core/fxge/win32/dwrite_int.h" +#include "core/include/fxge/fx_ge_win32.h" + +typedef HRESULT(__stdcall* FuncType_DWriteCreateFactory)( + __in DWRITE_FACTORY_TYPE, + __in REFIID, + __out IUnknown**); +template <typename InterfaceType> +inline void SafeRelease(InterfaceType** currentObject) { + if (*currentObject) { + (*currentObject)->Release(); + *currentObject = NULL; + } +} +template <typename InterfaceType> +inline InterfaceType* SafeAcquire(InterfaceType* newObject) { + if (newObject) { + newObject->AddRef(); + } + return newObject; +} +class CDwFontFileStream final : public IDWriteFontFileStream { + public: + explicit CDwFontFileStream(void const* fontFileReferenceKey, + UINT32 fontFileReferenceKeySize); + virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, + void** ppvObject); + virtual ULONG STDMETHODCALLTYPE AddRef(); + virtual ULONG STDMETHODCALLTYPE Release(); + virtual HRESULT STDMETHODCALLTYPE + ReadFileFragment(void const** fragmentStart, + UINT64 fileOffset, + UINT64 fragmentSize, + OUT void** fragmentContext); + virtual void STDMETHODCALLTYPE ReleaseFileFragment(void* fragmentContext); + virtual HRESULT STDMETHODCALLTYPE GetFileSize(OUT UINT64* fileSize); + virtual HRESULT STDMETHODCALLTYPE GetLastWriteTime(OUT UINT64* lastWriteTime); + bool IsInitialized() { return resourcePtr_ != NULL; } + + private: + ULONG refCount_; + void const* resourcePtr_; + DWORD resourceSize_; +}; +class CDwFontFileLoader final : public IDWriteFontFileLoader { + public: + virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, + void** ppvObject); + virtual ULONG STDMETHODCALLTYPE AddRef(); + virtual ULONG STDMETHODCALLTYPE Release(); + virtual HRESULT STDMETHODCALLTYPE + CreateStreamFromKey(void const* fontFileReferenceKey, + UINT32 fontFileReferenceKeySize, + OUT IDWriteFontFileStream** fontFileStream); + + static IDWriteFontFileLoader* GetLoader() { + if (!instance_) { + instance_ = new CDwFontFileLoader(); + } + return instance_; + } + static bool IsLoaderInitialized() { return instance_ != NULL; } + + private: + CDwFontFileLoader(); + ULONG refCount_; + static IDWriteFontFileLoader* instance_; +}; +class CDwFontContext { + public: + CDwFontContext(IDWriteFactory* dwriteFactory); + ~CDwFontContext(); + HRESULT Initialize(); + + private: + CDwFontContext(CDwFontContext const&); + void operator=(CDwFontContext const&); + HRESULT hr_; + IDWriteFactory* dwriteFactory_; +}; +class CDwGdiTextRenderer { + public: + CDwGdiTextRenderer(CFX_DIBitmap* pBitmap, + IDWriteBitmapRenderTarget* bitmapRenderTarget, + IDWriteRenderingParams* renderingParams); + ~CDwGdiTextRenderer(); + HRESULT STDMETHODCALLTYPE DrawGlyphRun(const FX_RECT& text_bbox, + __in_opt CFX_ClipRgn* pClipRgn, + __in_opt DWRITE_MATRIX const* pMatrix, + FLOAT baselineOriginX, + FLOAT baselineOriginY, + DWRITE_MEASURING_MODE measuringMode, + __in DWRITE_GLYPH_RUN const* glyphRun, + const COLORREF& textColor); + + private: + CFX_DIBitmap* pBitmap_; + IDWriteBitmapRenderTarget* pRenderTarget_; + IDWriteRenderingParams* pRenderingParams_; +}; +CDWriteExt::CDWriteExt() { + m_hModule = NULL; + m_pDWriteFactory = NULL; + m_pDwFontContext = NULL; + m_pDwTextRenderer = NULL; +} +void CDWriteExt::Load() {} +void CDWriteExt::Unload() { + if (m_pDwFontContext) { + delete (CDwFontContext*)m_pDwFontContext; + m_pDwFontContext = NULL; + } + SafeRelease((IDWriteFactory**)&m_pDWriteFactory); +} +CDWriteExt::~CDWriteExt() { + Unload(); +} +LPVOID CDWriteExt::DwCreateFontFaceFromStream(uint8_t* pData, + FX_DWORD size, + int simulation_style) { + IDWriteFactory* pDwFactory = (IDWriteFactory*)m_pDWriteFactory; + IDWriteFontFile* pDwFontFile = NULL; + IDWriteFontFace* pDwFontFace = NULL; + BOOL isSupportedFontType = FALSE; + DWRITE_FONT_FILE_TYPE fontFileType; + DWRITE_FONT_FACE_TYPE fontFaceType; + UINT32 numberOfFaces; + DWRITE_FONT_SIMULATIONS fontStyle = + (DWRITE_FONT_SIMULATIONS)(simulation_style & 3); + HRESULT hr = S_OK; + hr = pDwFactory->CreateCustomFontFileReference( + (void const*)pData, (UINT32)size, CDwFontFileLoader::GetLoader(), + &pDwFontFile); + if (FAILED(hr)) { + goto failed; + } + hr = pDwFontFile->Analyze(&isSupportedFontType, &fontFileType, &fontFaceType, + &numberOfFaces); + if (FAILED(hr) || !isSupportedFontType || + fontFaceType == DWRITE_FONT_FACE_TYPE_UNKNOWN) { + goto failed; + } + hr = pDwFactory->CreateFontFace(fontFaceType, 1, &pDwFontFile, 0, fontStyle, + &pDwFontFace); + if (FAILED(hr)) { + goto failed; + } + SafeRelease(&pDwFontFile); + return pDwFontFace; +failed: + SafeRelease(&pDwFontFile); + return NULL; +} +FX_BOOL CDWriteExt::DwCreateRenderingTarget(CFX_DIBitmap* pBitmap, + void** renderTarget) { + if (pBitmap->GetFormat() > FXDIB_Argb) { + return FALSE; + } + IDWriteFactory* pDwFactory = (IDWriteFactory*)m_pDWriteFactory; + IDWriteGdiInterop* pGdiInterop = NULL; + IDWriteBitmapRenderTarget* pBitmapRenderTarget = NULL; + IDWriteRenderingParams* pRenderingParams = NULL; + HRESULT hr = S_OK; + hr = pDwFactory->GetGdiInterop(&pGdiInterop); + if (FAILED(hr)) { + goto failed; + } + hr = pGdiInterop->CreateBitmapRenderTarget( + NULL, pBitmap->GetWidth(), pBitmap->GetHeight(), &pBitmapRenderTarget); + if (FAILED(hr)) { + goto failed; + } + hr = pDwFactory->CreateCustomRenderingParams( + 1.0f, 0.0f, 1.0f, DWRITE_PIXEL_GEOMETRY_RGB, + DWRITE_RENDERING_MODE_DEFAULT, &pRenderingParams); + if (FAILED(hr)) { + goto failed; + } + hr = pBitmapRenderTarget->SetPixelsPerDip(1.0f); + if (FAILED(hr)) { + goto failed; + } + *(CDwGdiTextRenderer**)renderTarget = + new CDwGdiTextRenderer(pBitmap, pBitmapRenderTarget, pRenderingParams); + SafeRelease(&pGdiInterop); + SafeRelease(&pBitmapRenderTarget); + SafeRelease(&pRenderingParams); + return TRUE; +failed: + SafeRelease(&pGdiInterop); + SafeRelease(&pBitmapRenderTarget); + SafeRelease(&pRenderingParams); + return FALSE; +} +FX_BOOL CDWriteExt::DwRendingString(void* renderTarget, + CFX_ClipRgn* pClipRgn, + FX_RECT& stringRect, + CFX_Matrix* pMatrix, + void* font, + FX_FLOAT font_size, + FX_ARGB text_color, + int glyph_count, + unsigned short* glyph_indices, + FX_FLOAT baselineOriginX, + FX_FLOAT baselineOriginY, + void* glyph_offsets, + FX_FLOAT* glyph_advances) { + if (!renderTarget) { + return TRUE; + } + CDwGdiTextRenderer* pTextRenderer = (CDwGdiTextRenderer*)renderTarget; + DWRITE_MATRIX transform; + DWRITE_GLYPH_RUN glyphRun; + HRESULT hr = S_OK; + if (pMatrix) { + transform.m11 = pMatrix->a; + transform.m12 = pMatrix->b; + transform.m21 = pMatrix->c; + transform.m22 = pMatrix->d; + transform.dx = pMatrix->e; + transform.dy = pMatrix->f; + } + glyphRun.fontFace = (IDWriteFontFace*)font; + glyphRun.fontEmSize = font_size; + glyphRun.glyphCount = glyph_count; + glyphRun.glyphIndices = glyph_indices; + glyphRun.glyphAdvances = glyph_advances; + glyphRun.glyphOffsets = (DWRITE_GLYPH_OFFSET*)glyph_offsets; + glyphRun.isSideways = FALSE; + glyphRun.bidiLevel = 0; + hr = pTextRenderer->DrawGlyphRun( + stringRect, pClipRgn, pMatrix ? &transform : NULL, baselineOriginX, + baselineOriginY, DWRITE_MEASURING_MODE_NATURAL, &glyphRun, + RGB(FXARGB_R(text_color), FXARGB_G(text_color), FXARGB_B(text_color))); + return SUCCEEDED(hr); +} +void CDWriteExt::DwDeleteRenderingTarget(void* renderTarget) { + delete (CDwGdiTextRenderer*)renderTarget; +} +void CDWriteExt::DwDeleteFont(void* pFont) { + if (pFont) { + SafeRelease((IDWriteFontFace**)&pFont); + } +} +CDwFontFileStream::CDwFontFileStream(void const* fontFileReferenceKey, + UINT32 fontFileReferenceKeySize) { + refCount_ = 0; + resourcePtr_ = fontFileReferenceKey; + resourceSize_ = fontFileReferenceKeySize; +} +HRESULT STDMETHODCALLTYPE CDwFontFileStream::QueryInterface(REFIID iid, + void** ppvObject) { + if (iid == IID_IUnknown || iid == __uuidof(IDWriteFontFileStream)) { + *ppvObject = this; + AddRef(); + return S_OK; + } + *ppvObject = NULL; + return E_NOINTERFACE; +} +ULONG STDMETHODCALLTYPE CDwFontFileStream::AddRef() { + return InterlockedIncrement((long*)(&refCount_)); +} +ULONG STDMETHODCALLTYPE CDwFontFileStream::Release() { + ULONG newCount = InterlockedDecrement((long*)(&refCount_)); + if (newCount == 0) { + delete this; + } + return newCount; +} +HRESULT STDMETHODCALLTYPE +CDwFontFileStream::ReadFileFragment(void const** fragmentStart, + UINT64 fileOffset, + UINT64 fragmentSize, + OUT void** fragmentContext) { + if (fileOffset <= resourceSize_ && + fragmentSize <= resourceSize_ - fileOffset) { + *fragmentStart = static_cast<uint8_t const*>(resourcePtr_) + + static_cast<size_t>(fileOffset); + *fragmentContext = NULL; + return S_OK; + } + *fragmentStart = NULL; + *fragmentContext = NULL; + return E_FAIL; +} +void STDMETHODCALLTYPE +CDwFontFileStream::ReleaseFileFragment(void* fragmentContext) {} +HRESULT STDMETHODCALLTYPE CDwFontFileStream::GetFileSize(OUT UINT64* fileSize) { + *fileSize = resourceSize_; + return S_OK; +} +HRESULT STDMETHODCALLTYPE +CDwFontFileStream::GetLastWriteTime(OUT UINT64* lastWriteTime) { + *lastWriteTime = 0; + return E_NOTIMPL; +} +IDWriteFontFileLoader* CDwFontFileLoader::instance_ = NULL; +CDwFontFileLoader::CDwFontFileLoader() : refCount_(0) {} +HRESULT STDMETHODCALLTYPE CDwFontFileLoader::QueryInterface(REFIID iid, + void** ppvObject) { + if (iid == IID_IUnknown || iid == __uuidof(IDWriteFontFileLoader)) { + *ppvObject = this; + AddRef(); + return S_OK; + } + *ppvObject = NULL; + return E_NOINTERFACE; +} +ULONG STDMETHODCALLTYPE CDwFontFileLoader::AddRef() { + return InterlockedIncrement((long*)(&refCount_)); +} +ULONG STDMETHODCALLTYPE CDwFontFileLoader::Release() { + ULONG newCount = InterlockedDecrement((long*)(&refCount_)); + if (newCount == 0) { + instance_ = NULL; + delete this; + } + return newCount; +} +HRESULT STDMETHODCALLTYPE CDwFontFileLoader::CreateStreamFromKey( + void const* fontFileReferenceKey, + UINT32 fontFileReferenceKeySize, + OUT IDWriteFontFileStream** fontFileStream) { + *fontFileStream = NULL; + CDwFontFileStream* stream = + new CDwFontFileStream(fontFileReferenceKey, fontFileReferenceKeySize); + if (!stream->IsInitialized()) { + delete stream; + return E_FAIL; + } + *fontFileStream = SafeAcquire(stream); + return S_OK; +} +CDwFontContext::CDwFontContext(IDWriteFactory* dwriteFactory) + : hr_(S_FALSE), dwriteFactory_(SafeAcquire(dwriteFactory)) {} +CDwFontContext::~CDwFontContext() { + if (dwriteFactory_ && hr_ == S_OK) { + dwriteFactory_->UnregisterFontFileLoader(CDwFontFileLoader::GetLoader()); + } + SafeRelease(&dwriteFactory_); +} +HRESULT CDwFontContext::Initialize() { + if (hr_ == S_FALSE) { + return hr_ = dwriteFactory_->RegisterFontFileLoader( + CDwFontFileLoader::GetLoader()); + } + return hr_; +} +CDwGdiTextRenderer::CDwGdiTextRenderer( + CFX_DIBitmap* pBitmap, + IDWriteBitmapRenderTarget* bitmapRenderTarget, + IDWriteRenderingParams* renderingParams) + : pBitmap_(pBitmap), + pRenderTarget_(SafeAcquire(bitmapRenderTarget)), + pRenderingParams_(SafeAcquire(renderingParams)) {} +CDwGdiTextRenderer::~CDwGdiTextRenderer() { + SafeRelease(&pRenderTarget_); + SafeRelease(&pRenderingParams_); +} +STDMETHODIMP CDwGdiTextRenderer::DrawGlyphRun( + const FX_RECT& text_bbox, + __in_opt CFX_ClipRgn* pClipRgn, + __in_opt DWRITE_MATRIX const* pMatrix, + FLOAT baselineOriginX, + FLOAT baselineOriginY, + DWRITE_MEASURING_MODE measuringMode, + __in DWRITE_GLYPH_RUN const* glyphRun, + const COLORREF& textColor) { + HRESULT hr = S_OK; + if (pMatrix) { + hr = pRenderTarget_->SetCurrentTransform(pMatrix); + if (FAILED(hr)) { + return hr; + } + } + HDC hDC = pRenderTarget_->GetMemoryDC(); + HBITMAP hBitmap = (HBITMAP)::GetCurrentObject(hDC, OBJ_BITMAP); + BITMAP bitmap; + GetObject(hBitmap, sizeof bitmap, &bitmap); + CFX_DIBitmap dib; + dib.Create(bitmap.bmWidth, bitmap.bmHeight, + bitmap.bmBitsPixel == 24 ? FXDIB_Rgb : FXDIB_Rgb32, + (uint8_t*)bitmap.bmBits); + dib.CompositeBitmap(text_bbox.left, text_bbox.top, text_bbox.Width(), + text_bbox.Height(), pBitmap_, text_bbox.left, + text_bbox.top, FXDIB_BLEND_NORMAL, NULL); + hr = pRenderTarget_->DrawGlyphRun(baselineOriginX, baselineOriginY, + measuringMode, glyphRun, pRenderingParams_, + textColor); + if (FAILED(hr)) { + return hr; + } + pBitmap_->CompositeBitmap(text_bbox.left, text_bbox.top, text_bbox.Width(), + text_bbox.Height(), &dib, text_bbox.left, + text_bbox.top, FXDIB_BLEND_NORMAL, pClipRgn); + return hr; +} +#endif diff --git a/core/fxge/win32/fx_win32_gdipext.cpp b/core/fxge/win32/fx_win32_gdipext.cpp new file mode 100644 index 0000000000..ce181bb448 --- /dev/null +++ b/core/fxge/win32/fx_win32_gdipext.cpp @@ -0,0 +1,1518 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "core/include/fxge/fx_ge.h" + +#if _FX_OS_ == _FX_WIN32_DESKTOP_ || _FX_OS_ == _FX_WIN64_DESKTOP_ +#include <windows.h> +#include <algorithm> + +namespace Gdiplus { +using std::min; +using std::max; +} // namespace Gdiplus + +#include <gdiplus.h> + +#include "core/fxge/win32/win32_int.h" +#include "core/include/fxge/fx_ge_win32.h" + +using namespace Gdiplus; // NOLINT +using namespace Gdiplus::DllExports; // NOLINT + +#define GdiFillType2Gdip(fill_type) \ + (fill_type == ALTERNATE ? FillModeAlternate : FillModeWinding) + +enum { + FuncId_GdipCreatePath2, + FuncId_GdipSetPenDashStyle, + FuncId_GdipSetPenDashArray, + FuncId_GdipSetPenDashCap197819, + FuncId_GdipSetPenLineJoin, + FuncId_GdipSetPenWidth, + FuncId_GdipCreateFromHDC, + FuncId_GdipSetPageUnit, + FuncId_GdipSetSmoothingMode, + FuncId_GdipCreateSolidFill, + FuncId_GdipFillPath, + FuncId_GdipDeleteBrush, + FuncId_GdipCreatePen1, + FuncId_GdipSetPenMiterLimit, + FuncId_GdipDrawPath, + FuncId_GdipDeletePen, + FuncId_GdipDeletePath, + FuncId_GdipDeleteGraphics, + FuncId_GdipCreateBitmapFromFileICM, + FuncId_GdipCreateBitmapFromStreamICM, + FuncId_GdipGetImageHeight, + FuncId_GdipGetImageWidth, + FuncId_GdipGetImagePixelFormat, + FuncId_GdipBitmapLockBits, + FuncId_GdipGetImagePaletteSize, + FuncId_GdipGetImagePalette, + FuncId_GdipBitmapUnlockBits, + FuncId_GdipDisposeImage, + FuncId_GdipFillRectangle, + FuncId_GdipCreateBitmapFromScan0, + FuncId_GdipSetImagePalette, + FuncId_GdipSetInterpolationMode, + FuncId_GdipDrawImagePointsI, + FuncId_GdipCreateBitmapFromGdiDib, + FuncId_GdiplusStartup, + FuncId_GdipDrawLineI, + FuncId_GdipResetClip, + FuncId_GdipCreatePath, + FuncId_GdipAddPathPath, + FuncId_GdipSetPathFillMode, + FuncId_GdipSetClipPath, + FuncId_GdipGetClip, + FuncId_GdipCreateRegion, + FuncId_GdipGetClipBoundsI, + FuncId_GdipSetClipRegion, + FuncId_GdipWidenPath, + FuncId_GdipAddPathLine, + FuncId_GdipAddPathRectangle, + FuncId_GdipDeleteRegion, + FuncId_GdipGetDC, + FuncId_GdipReleaseDC, + FuncId_GdipSetPenLineCap197819, + FuncId_GdipSetPenDashOffset, + FuncId_GdipResetPath, + FuncId_GdipCreateRegionPath, + FuncId_GdipCreateFont, + FuncId_GdipGetFontSize, + FuncId_GdipCreateFontFamilyFromName, + FuncId_GdipSetTextRenderingHint, + FuncId_GdipDrawDriverString, + FuncId_GdipCreateMatrix2, + FuncId_GdipDeleteMatrix, + FuncId_GdipSetWorldTransform, + FuncId_GdipResetWorldTransform, + FuncId_GdipDeleteFontFamily, + FuncId_GdipDeleteFont, + FuncId_GdipNewPrivateFontCollection, + FuncId_GdipDeletePrivateFontCollection, + FuncId_GdipPrivateAddMemoryFont, + FuncId_GdipGetFontCollectionFamilyList, + FuncId_GdipGetFontCollectionFamilyCount, + FuncId_GdipSetTextContrast, + FuncId_GdipSetPixelOffsetMode, + FuncId_GdipGetImageGraphicsContext, + FuncId_GdipDrawImageI, + FuncId_GdipDrawImageRectI, + FuncId_GdipDrawString, + FuncId_GdipSetPenTransform, +}; +static LPCSTR g_GdipFuncNames[] = { + "GdipCreatePath2", + "GdipSetPenDashStyle", + "GdipSetPenDashArray", + "GdipSetPenDashCap197819", + "GdipSetPenLineJoin", + "GdipSetPenWidth", + "GdipCreateFromHDC", + "GdipSetPageUnit", + "GdipSetSmoothingMode", + "GdipCreateSolidFill", + "GdipFillPath", + "GdipDeleteBrush", + "GdipCreatePen1", + "GdipSetPenMiterLimit", + "GdipDrawPath", + "GdipDeletePen", + "GdipDeletePath", + "GdipDeleteGraphics", + "GdipCreateBitmapFromFileICM", + "GdipCreateBitmapFromStreamICM", + "GdipGetImageHeight", + "GdipGetImageWidth", + "GdipGetImagePixelFormat", + "GdipBitmapLockBits", + "GdipGetImagePaletteSize", + "GdipGetImagePalette", + "GdipBitmapUnlockBits", + "GdipDisposeImage", + "GdipFillRectangle", + "GdipCreateBitmapFromScan0", + "GdipSetImagePalette", + "GdipSetInterpolationMode", + "GdipDrawImagePointsI", + "GdipCreateBitmapFromGdiDib", + "GdiplusStartup", + "GdipDrawLineI", + "GdipResetClip", + "GdipCreatePath", + "GdipAddPathPath", + "GdipSetPathFillMode", + "GdipSetClipPath", + "GdipGetClip", + "GdipCreateRegion", + "GdipGetClipBoundsI", + "GdipSetClipRegion", + "GdipWidenPath", + "GdipAddPathLine", + "GdipAddPathRectangle", + "GdipDeleteRegion", + "GdipGetDC", + "GdipReleaseDC", + "GdipSetPenLineCap197819", + "GdipSetPenDashOffset", + "GdipResetPath", + "GdipCreateRegionPath", + "GdipCreateFont", + "GdipGetFontSize", + "GdipCreateFontFamilyFromName", + "GdipSetTextRenderingHint", + "GdipDrawDriverString", + "GdipCreateMatrix2", + "GdipDeleteMatrix", + "GdipSetWorldTransform", + "GdipResetWorldTransform", + "GdipDeleteFontFamily", + "GdipDeleteFont", + "GdipNewPrivateFontCollection", + "GdipDeletePrivateFontCollection", + "GdipPrivateAddMemoryFont", + "GdipGetFontCollectionFamilyList", + "GdipGetFontCollectionFamilyCount", + "GdipSetTextContrast", + "GdipSetPixelOffsetMode", + "GdipGetImageGraphicsContext", + "GdipDrawImageI", + "GdipDrawImageRectI", + "GdipDrawString", + "GdipSetPenTransform", +}; +typedef GpStatus(WINGDIPAPI* FuncType_GdipCreatePath2)(GDIPCONST GpPointF*, + GDIPCONST BYTE*, + INT, + GpFillMode, + GpPath** path); +typedef GpStatus(WINGDIPAPI* FuncType_GdipSetPenDashStyle)( + GpPen* pen, + GpDashStyle dashstyle); +typedef GpStatus(WINGDIPAPI* FuncType_GdipSetPenDashArray)(GpPen* pen, + GDIPCONST REAL* dash, + INT count); +typedef GpStatus(WINGDIPAPI* FuncType_GdipSetPenDashCap197819)( + GpPen* pen, + GpDashCap dashCap); +typedef GpStatus(WINGDIPAPI* FuncType_GdipSetPenLineJoin)(GpPen* pen, + GpLineJoin lineJoin); +typedef GpStatus(WINGDIPAPI* FuncType_GdipSetPenWidth)(GpPen* pen, REAL width); +typedef GpStatus(WINGDIPAPI* FuncType_GdipCreateFromHDC)(HDC hdc, + GpGraphics** graphics); +typedef GpStatus(WINGDIPAPI* FuncType_GdipSetPageUnit)(GpGraphics* graphics, + GpUnit unit); +typedef GpStatus(WINGDIPAPI* FuncType_GdipSetSmoothingMode)( + GpGraphics* graphics, + SmoothingMode smoothingMode); +typedef GpStatus(WINGDIPAPI* FuncType_GdipCreateSolidFill)(ARGB color, + GpSolidFill** brush); +typedef GpStatus(WINGDIPAPI* FuncType_GdipFillPath)(GpGraphics* graphics, + GpBrush* brush, + GpPath* path); +typedef GpStatus(WINGDIPAPI* FuncType_GdipDeleteBrush)(GpBrush* brush); +typedef GpStatus(WINGDIPAPI* FuncType_GdipCreatePen1)(ARGB color, + REAL width, + GpUnit unit, + GpPen** pen); +typedef GpStatus(WINGDIPAPI* FuncType_GdipSetPenMiterLimit)(GpPen* pen, + REAL miterLimit); +typedef GpStatus(WINGDIPAPI* FuncType_GdipDrawPath)(GpGraphics* graphics, + GpPen* pen, + GpPath* path); +typedef GpStatus(WINGDIPAPI* FuncType_GdipDeletePen)(GpPen* pen); +typedef GpStatus(WINGDIPAPI* FuncType_GdipDeletePath)(GpPath* path); +typedef GpStatus(WINGDIPAPI* FuncType_GdipDeleteGraphics)(GpGraphics* graphics); +typedef GpStatus(WINGDIPAPI* FuncType_GdipCreateBitmapFromFileICM)( + GDIPCONST WCHAR* filename, + GpBitmap** bitmap); +typedef GpStatus(WINGDIPAPI* FuncType_GdipCreateBitmapFromStreamICM)( + IStream* stream, + GpBitmap** bitmap); +typedef GpStatus(WINGDIPAPI* FuncType_GdipGetImageWidth)(GpImage* image, + UINT* width); +typedef GpStatus(WINGDIPAPI* FuncType_GdipGetImageHeight)(GpImage* image, + UINT* height); +typedef GpStatus(WINGDIPAPI* FuncType_GdipGetImagePixelFormat)( + GpImage* image, + PixelFormat* format); +typedef GpStatus(WINGDIPAPI* FuncType_GdipBitmapLockBits)( + GpBitmap* bitmap, + GDIPCONST GpRect* rect, + UINT flags, + PixelFormat format, + BitmapData* lockedBitmapData); +typedef GpStatus(WINGDIPAPI* FuncType_GdipGetImagePalette)( + GpImage* image, + ColorPalette* palette, + INT size); +typedef GpStatus(WINGDIPAPI* FuncType_GdipGetImagePaletteSize)(GpImage* image, + INT* size); +typedef GpStatus(WINGDIPAPI* FuncType_GdipBitmapUnlockBits)( + GpBitmap* bitmap, + BitmapData* lockedBitmapData); +typedef GpStatus(WINGDIPAPI* FuncType_GdipDisposeImage)(GpImage* image); +typedef GpStatus(WINGDIPAPI* FuncType_GdipFillRectangle)(GpGraphics* graphics, + GpBrush* brush, + REAL x, + REAL y, + REAL width, + REAL height); +typedef GpStatus(WINGDIPAPI* FuncType_GdipCreateBitmapFromScan0)( + INT width, + INT height, + INT stride, + PixelFormat format, + BYTE* scan0, + GpBitmap** bitmap); +typedef GpStatus(WINGDIPAPI* FuncType_GdipSetImagePalette)( + GpImage* image, + GDIPCONST ColorPalette* palette); +typedef GpStatus(WINGDIPAPI* FuncType_GdipSetInterpolationMode)( + GpGraphics* graphics, + InterpolationMode interpolationMode); +typedef GpStatus(WINGDIPAPI* FuncType_GdipDrawImagePointsI)( + GpGraphics* graphics, + GpImage* image, + GDIPCONST GpPoint* dstpoints, + INT count); +typedef GpStatus(WINGDIPAPI* FuncType_GdipCreateBitmapFromGdiDib)( + GDIPCONST BITMAPINFO* gdiBitmapInfo, + VOID* gdiBitmapData, + GpBitmap** bitmap); +typedef Status(WINAPI* FuncType_GdiplusStartup)( + OUT uintptr_t* token, + const GdiplusStartupInput* input, + OUT GdiplusStartupOutput* output); +typedef GpStatus(WINGDIPAPI* FuncType_GdipDrawLineI)(GpGraphics* graphics, + GpPen* pen, + int x1, + int y1, + int x2, + int y2); +typedef GpStatus(WINGDIPAPI* FuncType_GdipResetClip)(GpGraphics* graphics); +typedef GpStatus(WINGDIPAPI* FuncType_GdipCreatePath)(GpFillMode brushMode, + GpPath** path); +typedef GpStatus(WINGDIPAPI* FuncType_GdipAddPathPath)( + GpPath* path, + GDIPCONST GpPath* addingPath, + BOOL connect); +typedef GpStatus(WINGDIPAPI* FuncType_GdipSetPathFillMode)(GpPath* path, + GpFillMode fillmode); +typedef GpStatus(WINGDIPAPI* FuncType_GdipSetClipPath)(GpGraphics* graphics, + GpPath* path, + CombineMode combineMode); +typedef GpStatus(WINGDIPAPI* FuncType_GdipGetClip)(GpGraphics* graphics, + GpRegion* region); +typedef GpStatus(WINGDIPAPI* FuncType_GdipCreateRegion)(GpRegion** region); +typedef GpStatus(WINGDIPAPI* FuncType_GdipGetClipBoundsI)(GpGraphics* graphics, + GpRect* rect); +typedef GpStatus(WINGDIPAPI* FuncType_GdipSetClipRegion)( + GpGraphics* graphics, + GpRegion* region, + CombineMode combineMode); +typedef GpStatus(WINGDIPAPI* FuncType_GdipWidenPath)(GpPath* nativePath, + GpPen* pen, + GpMatrix* matrix, + REAL flatness); +typedef GpStatus(WINGDIPAPI* FuncType_GdipAddPathLine)(GpPath* path, + REAL x1, + REAL y1, + REAL x2, + REAL y2); +typedef GpStatus(WINGDIPAPI* FuncType_GdipAddPathRectangle)(GpPath* path, + REAL x, + REAL y, + REAL width, + REAL height); +typedef GpStatus(WINGDIPAPI* FuncType_GdipDeleteRegion)(GpRegion* region); +typedef GpStatus(WINGDIPAPI* FuncType_GdipGetDC)(GpGraphics* graphics, + HDC* hdc); +typedef GpStatus(WINGDIPAPI* FuncType_GdipReleaseDC)(GpGraphics* graphics, + HDC hdc); +typedef GpStatus(WINGDIPAPI* FuncType_GdipSetPenLineCap197819)( + GpPen* pen, + GpLineCap startCap, + GpLineCap endCap, + GpDashCap dashCap); +typedef GpStatus(WINGDIPAPI* FuncType_GdipSetPenDashOffset)(GpPen* pen, + REAL offset); +typedef GpStatus(WINGDIPAPI* FuncType_GdipResetPath)(GpPath* path); +typedef GpStatus(WINGDIPAPI* FuncType_GdipCreateRegionPath)(GpPath* path, + GpRegion** region); +typedef GpStatus(WINGDIPAPI* FuncType_GdipCreateFont)( + GDIPCONST GpFontFamily* fontFamily, + REAL emSize, + INT style, + Unit unit, + GpFont** font); +typedef GpStatus(WINGDIPAPI* FuncType_GdipGetFontSize)(GpFont* font, + REAL* size); +typedef GpStatus(WINGDIPAPI* FuncType_GdipCreateFontFamilyFromName)( + GDIPCONST WCHAR* name, + GpFontCollection* fontCollection, + GpFontFamily** FontFamily); +typedef GpStatus(WINGDIPAPI* FuncType_GdipSetTextRenderingHint)( + GpGraphics* graphics, + TextRenderingHint mode); +typedef GpStatus(WINGDIPAPI* FuncType_GdipDrawDriverString)( + GpGraphics* graphics, + GDIPCONST UINT16* text, + INT length, + GDIPCONST GpFont* font, + GDIPCONST GpBrush* brush, + GDIPCONST PointF* positions, + INT flags, + GDIPCONST GpMatrix* matrix); +typedef GpStatus(WINGDIPAPI* FuncType_GdipCreateMatrix2)(REAL m11, + REAL m12, + REAL m21, + REAL m22, + REAL dx, + REAL dy, + GpMatrix** matrix); +typedef GpStatus(WINGDIPAPI* FuncType_GdipDeleteMatrix)(GpMatrix* matrix); +typedef GpStatus(WINGDIPAPI* FuncType_GdipSetWorldTransform)( + GpGraphics* graphics, + GpMatrix* matrix); +typedef GpStatus(WINGDIPAPI* FuncType_GdipResetWorldTransform)( + GpGraphics* graphics); +typedef GpStatus(WINGDIPAPI* FuncType_GdipDeleteFontFamily)( + GpFontFamily* FontFamily); +typedef GpStatus(WINGDIPAPI* FuncType_GdipDeleteFont)(GpFont* font); +typedef GpStatus(WINGDIPAPI* FuncType_GdipNewPrivateFontCollection)( + GpFontCollection** fontCollection); +typedef GpStatus(WINGDIPAPI* FuncType_GdipDeletePrivateFontCollection)( + GpFontCollection** fontCollection); +typedef GpStatus(WINGDIPAPI* FuncType_GdipPrivateAddMemoryFont)( + GpFontCollection* fontCollection, + GDIPCONST void* memory, + INT length); +typedef GpStatus(WINGDIPAPI* FuncType_GdipGetFontCollectionFamilyList)( + GpFontCollection* fontCollection, + INT numSought, + GpFontFamily* gpfamilies[], + INT* numFound); +typedef GpStatus(WINGDIPAPI* FuncType_GdipGetFontCollectionFamilyCount)( + GpFontCollection* fontCollection, + INT* numFound); +typedef GpStatus(WINGDIPAPI* FuncType_GdipSetTextContrast)(GpGraphics* graphics, + UINT contrast); +typedef GpStatus(WINGDIPAPI* FuncType_GdipSetPixelOffsetMode)( + GpGraphics* graphics, + PixelOffsetMode pixelOffsetMode); +typedef GpStatus(WINGDIPAPI* FuncType_GdipGetImageGraphicsContext)( + GpImage* image, + GpGraphics** graphics); +typedef GpStatus(WINGDIPAPI* FuncType_GdipDrawImageI)(GpGraphics* graphics, + GpImage* image, + INT x, + INT y); +typedef GpStatus(WINGDIPAPI* FuncType_GdipDrawImageRectI)(GpGraphics* graphics, + GpImage* image, + INT x, + INT y, + INT width, + INT height); +typedef GpStatus(WINGDIPAPI* FuncType_GdipDrawString)( + GpGraphics* graphics, + GDIPCONST WCHAR* str, + INT length, + GDIPCONST GpFont* font, + GDIPCONST RectF* layoutRect, + GDIPCONST GpStringFormat* stringFormat, + GDIPCONST GpBrush* brush); +typedef GpStatus(WINGDIPAPI* FuncType_GdipSetPenTransform)(GpPen* pen, + GpMatrix* matrix); +#define CallFunc(funcname) \ + ((FuncType_##funcname)GdiplusExt.m_Functions[FuncId_##funcname]) +typedef HANDLE(__stdcall* FuncType_GdiAddFontMemResourceEx)(PVOID pbFont, + DWORD cbFont, + PVOID pdv, + DWORD* pcFonts); +typedef BOOL(__stdcall* FuncType_GdiRemoveFontMemResourceEx)(HANDLE handle); +void* CGdiplusExt::GdiAddFontMemResourceEx(void* pFontdata, + FX_DWORD size, + void* pdv, + FX_DWORD* num_face) { + if (m_pGdiAddFontMemResourceEx) { + return ((FuncType_GdiAddFontMemResourceEx)m_pGdiAddFontMemResourceEx)( + (PVOID)pFontdata, (DWORD)size, (PVOID)pdv, (DWORD*)num_face); + } + return NULL; +} +FX_BOOL CGdiplusExt::GdiRemoveFontMemResourceEx(void* handle) { + if (m_pGdiRemoveFontMemResourseEx) { + return ((FuncType_GdiRemoveFontMemResourceEx)m_pGdiRemoveFontMemResourseEx)( + (HANDLE)handle); + } + return FALSE; +} +static GpBrush* _GdipCreateBrush(DWORD argb) { + CGdiplusExt& GdiplusExt = + ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt; + GpSolidFill* solidBrush = NULL; + CallFunc(GdipCreateSolidFill)((ARGB)argb, &solidBrush); + return solidBrush; +} +static CFX_DIBitmap* _StretchMonoToGray(int dest_width, + int dest_height, + const CFX_DIBitmap* pSource, + FX_RECT* pClipRect) { + FX_BOOL bFlipX = dest_width < 0; + if (bFlipX) { + dest_width = -dest_width; + } + FX_BOOL bFlipY = dest_height < 0; + if (bFlipY) { + dest_height = -dest_height; + } + int result_width = pClipRect->Width(); + int result_height = pClipRect->Height(); + int result_pitch = (result_width + 3) / 4 * 4; + CFX_DIBitmap* pStretched = new CFX_DIBitmap; + if (!pStretched->Create(result_width, result_height, FXDIB_8bppRgb)) { + delete pStretched; + return NULL; + } + LPBYTE dest_buf = pStretched->GetBuffer(); + int src_width = pSource->GetWidth(); + int src_height = pSource->GetHeight(); + int y_unit = src_height / dest_height; + int x_unit = src_width / dest_width; + int area_unit = y_unit * x_unit; + LPBYTE src_buf = pSource->GetBuffer(); + int src_pitch = pSource->GetPitch(); + for (int dest_y = 0; dest_y < result_height; dest_y++) { + LPBYTE dest_scan = dest_buf + dest_y * result_pitch; + int src_y_start = bFlipY ? (dest_height - 1 - dest_y - pClipRect->top) + : (dest_y + pClipRect->top); + src_y_start = src_y_start * src_height / dest_height; + LPBYTE src_scan = src_buf + src_y_start * src_pitch; + for (int dest_x = 0; dest_x < result_width; dest_x++) { + int sum = 0; + int src_x_start = bFlipX ? (dest_width - 1 - dest_x - pClipRect->left) + : (dest_x + pClipRect->left); + src_x_start = src_x_start * src_width / dest_width; + int src_x_end = src_x_start + x_unit; + LPBYTE src_line = src_scan; + for (int src_y = 0; src_y < y_unit; src_y++) { + for (int src_x = src_x_start; src_x < src_x_end; src_x++) { + if (!(src_line[src_x / 8] & (1 << (7 - src_x % 8)))) { + sum += 255; + } + } + src_line += src_pitch; + } + dest_scan[dest_x] = 255 - sum / area_unit; + } + } + return pStretched; +} +static void OutputImageMask(GpGraphics* pGraphics, + BOOL bMonoDevice, + const CFX_DIBitmap* pBitmap, + int dest_left, + int dest_top, + int dest_width, + int dest_height, + FX_ARGB argb, + const FX_RECT* pClipRect) { + ASSERT(pBitmap->GetBPP() == 1); + CGdiplusExt& GdiplusExt = + ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt; + int src_width = pBitmap->GetWidth(), src_height = pBitmap->GetHeight(); + int src_pitch = pBitmap->GetPitch(); + uint8_t* scan0 = pBitmap->GetBuffer(); + if (src_width == 1 && src_height == 1) { + if ((scan0[0] & 0x80) == 0) { + return; + } + GpSolidFill* solidBrush; + CallFunc(GdipCreateSolidFill)((ARGB)argb, &solidBrush); + if (dest_width < 0) { + dest_width = -dest_width; + dest_left -= dest_width; + } + if (dest_height < 0) { + dest_height = -dest_height; + dest_top -= dest_height; + } + CallFunc(GdipFillRectangle)(pGraphics, solidBrush, (float)dest_left, + (float)dest_top, (float)dest_width, + (float)dest_height); + CallFunc(GdipDeleteBrush)(solidBrush); + return; + } + if (!bMonoDevice && abs(dest_width) < src_width && + abs(dest_height) < src_height) { + FX_RECT image_rect(dest_left, dest_top, dest_left + dest_width, + dest_top + dest_height); + image_rect.Normalize(); + FX_RECT image_clip = image_rect; + image_clip.Intersect(*pClipRect); + if (image_clip.IsEmpty()) { + return; + } + image_clip.Offset(-image_rect.left, -image_rect.top); + CFX_DIBitmap* pStretched = NULL; + if (src_width * src_height > 10000) { + pStretched = + _StretchMonoToGray(dest_width, dest_height, pBitmap, &image_clip); + } else { + pStretched = + pBitmap->StretchTo(dest_width, dest_height, FALSE, &image_clip); + } + GpBitmap* bitmap; + CallFunc(GdipCreateBitmapFromScan0)(image_clip.Width(), image_clip.Height(), + (image_clip.Width() + 3) / 4 * 4, + PixelFormat8bppIndexed, + pStretched->GetBuffer(), &bitmap); + int a, r, g, b; + ArgbDecode(argb, a, r, g, b); + UINT pal[258]; + pal[0] = 0; + pal[1] = 256; + for (int i = 0; i < 256; i++) { + pal[i + 2] = ArgbEncode(i * a / 255, r, g, b); + } + CallFunc(GdipSetImagePalette)(bitmap, (ColorPalette*)pal); + CallFunc(GdipDrawImageI)(pGraphics, bitmap, + image_rect.left + image_clip.left, + image_rect.top + image_clip.top); + CallFunc(GdipDisposeImage)(bitmap); + delete pStretched; + return; + } + GpBitmap* bitmap; + CallFunc(GdipCreateBitmapFromScan0)(src_width, src_height, src_pitch, + PixelFormat1bppIndexed, scan0, &bitmap); + UINT palette[4] = {PaletteFlagsHasAlpha, 2, 0, argb}; + CallFunc(GdipSetImagePalette)(bitmap, (ColorPalette*)palette); + Point destinationPoints[] = {Point(dest_left, dest_top), + Point(dest_left + dest_width, dest_top), + Point(dest_left, dest_top + dest_height)}; + CallFunc(GdipDrawImagePointsI)(pGraphics, bitmap, destinationPoints, 3); + CallFunc(GdipDisposeImage)(bitmap); +} +static void OutputImage(GpGraphics* pGraphics, + const CFX_DIBitmap* pBitmap, + const FX_RECT* pSrcRect, + int dest_left, + int dest_top, + int dest_width, + int dest_height) { + int src_width = pSrcRect->Width(), src_height = pSrcRect->Height(); + CGdiplusExt& GdiplusExt = + ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt; + if (pBitmap->GetBPP() == 1 && (pSrcRect->left % 8)) { + FX_RECT new_rect(0, 0, src_width, src_height); + CFX_DIBitmap* pCloned = pBitmap->Clone(pSrcRect); + if (!pCloned) { + return; + } + OutputImage(pGraphics, pCloned, &new_rect, dest_left, dest_top, dest_width, + dest_height); + delete pCloned; + return; + } + int src_pitch = pBitmap->GetPitch(); + uint8_t* scan0 = pBitmap->GetBuffer() + pSrcRect->top * src_pitch + + pBitmap->GetBPP() * pSrcRect->left / 8; + GpBitmap* bitmap = NULL; + switch (pBitmap->GetFormat()) { + case FXDIB_Argb: + CallFunc(GdipCreateBitmapFromScan0)(src_width, src_height, src_pitch, + PixelFormat32bppARGB, scan0, &bitmap); + break; + case FXDIB_Rgb32: + CallFunc(GdipCreateBitmapFromScan0)(src_width, src_height, src_pitch, + PixelFormat32bppRGB, scan0, &bitmap); + break; + case FXDIB_Rgb: + CallFunc(GdipCreateBitmapFromScan0)(src_width, src_height, src_pitch, + PixelFormat24bppRGB, scan0, &bitmap); + break; + case FXDIB_8bppRgb: { + CallFunc(GdipCreateBitmapFromScan0)(src_width, src_height, src_pitch, + PixelFormat8bppIndexed, scan0, + &bitmap); + UINT pal[258]; + pal[0] = 0; + pal[1] = 256; + for (int i = 0; i < 256; i++) { + pal[i + 2] = pBitmap->GetPaletteEntry(i); + } + CallFunc(GdipSetImagePalette)(bitmap, (ColorPalette*)pal); + break; + } + case FXDIB_1bppRgb: { + CallFunc(GdipCreateBitmapFromScan0)(src_width, src_height, src_pitch, + PixelFormat1bppIndexed, scan0, + &bitmap); + break; + } + } + if (dest_height < 0) { + dest_height--; + } + if (dest_width < 0) { + dest_width--; + } + Point destinationPoints[] = {Point(dest_left, dest_top), + Point(dest_left + dest_width, dest_top), + Point(dest_left, dest_top + dest_height)}; + CallFunc(GdipDrawImagePointsI)(pGraphics, bitmap, destinationPoints, 3); + CallFunc(GdipDisposeImage)(bitmap); +} +CGdiplusExt::CGdiplusExt() { + m_hModule = NULL; + m_GdiModule = NULL; + for (int i = 0; i < sizeof g_GdipFuncNames / sizeof(LPCSTR); i++) { + m_Functions[i] = NULL; + } + m_pGdiAddFontMemResourceEx = NULL; + m_pGdiRemoveFontMemResourseEx = NULL; +} +void CGdiplusExt::Load() { + CFX_ByteString strPlusPath = ""; + FX_CHAR buf[MAX_PATH]; + GetSystemDirectoryA(buf, MAX_PATH); + strPlusPath += buf; + strPlusPath += "\\"; + strPlusPath += "GDIPLUS.DLL"; + m_hModule = LoadLibraryA(strPlusPath); + if (!m_hModule) { + return; + } + for (int i = 0; i < sizeof g_GdipFuncNames / sizeof(LPCSTR); i++) { + m_Functions[i] = GetProcAddress(m_hModule, g_GdipFuncNames[i]); + if (!m_Functions[i]) { + m_hModule = NULL; + return; + } + } + uintptr_t gdiplusToken; + GdiplusStartupInput gdiplusStartupInput; + ((FuncType_GdiplusStartup)m_Functions[FuncId_GdiplusStartup])( + &gdiplusToken, &gdiplusStartupInput, NULL); + m_GdiModule = LoadLibraryA("GDI32.DLL"); + if (!m_GdiModule) { + return; + } + m_pGdiAddFontMemResourceEx = + GetProcAddress(m_GdiModule, "AddFontMemResourceEx"); + m_pGdiRemoveFontMemResourseEx = + GetProcAddress(m_GdiModule, "RemoveFontMemResourceEx"); +} +CGdiplusExt::~CGdiplusExt() {} +LPVOID CGdiplusExt::LoadMemFont(LPBYTE pData, FX_DWORD size) { + GpFontCollection* pCollection = NULL; + CGdiplusExt& GdiplusExt = + ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt; + CallFunc(GdipNewPrivateFontCollection)(&pCollection); + GpStatus status = + CallFunc(GdipPrivateAddMemoryFont)(pCollection, pData, size); + if (status == Ok) { + return pCollection; + } + CallFunc(GdipDeletePrivateFontCollection)(&pCollection); + return NULL; +} +void CGdiplusExt::DeleteMemFont(LPVOID pCollection) { + CGdiplusExt& GdiplusExt = + ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt; + CallFunc(GdipDeletePrivateFontCollection)((GpFontCollection**)&pCollection); +} +FX_BOOL CGdiplusExt::GdipCreateBitmap(CFX_DIBitmap* pBitmap, void** bitmap) { + CGdiplusExt& GdiplusExt = + ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt; + PixelFormat format; + switch (pBitmap->GetFormat()) { + case FXDIB_Rgb: + format = PixelFormat24bppRGB; + break; + case FXDIB_Rgb32: + format = PixelFormat32bppRGB; + break; + case FXDIB_Argb: + format = PixelFormat32bppARGB; + break; + default: + return FALSE; + } + GpStatus status = CallFunc(GdipCreateBitmapFromScan0)( + pBitmap->GetWidth(), pBitmap->GetHeight(), pBitmap->GetPitch(), format, + pBitmap->GetBuffer(), (GpBitmap**)bitmap); + if (status == Ok) { + return TRUE; + } + return FALSE; +} +FX_BOOL CGdiplusExt::GdipCreateFromImage(void* bitmap, void** graphics) { + CGdiplusExt& GdiplusExt = + ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt; + GpStatus status = CallFunc(GdipGetImageGraphicsContext)( + (GpBitmap*)bitmap, (GpGraphics**)graphics); + if (status == Ok) { + return TRUE; + } + return FALSE; +} +FX_BOOL CGdiplusExt::GdipCreateFontFamilyFromName(const FX_WCHAR* name, + void* pFontCollection, + void** pFamily) { + CGdiplusExt& GdiplusExt = + ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt; + GpStatus status = CallFunc(GdipCreateFontFamilyFromName)( + (GDIPCONST WCHAR*)name, (GpFontCollection*)pFontCollection, + (GpFontFamily**)pFamily); + if (status == Ok) { + return TRUE; + } + return FALSE; +} +FX_BOOL CGdiplusExt::GdipCreateFontFromFamily(void* pFamily, + FX_FLOAT font_size, + int fontstyle, + int flag, + void** pFont) { + CGdiplusExt& GdiplusExt = + ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt; + GpStatus status = + CallFunc(GdipCreateFont)((GpFontFamily*)pFamily, font_size, fontstyle, + Unit(flag), (GpFont**)pFont); + if (status == Ok) { + return TRUE; + } + return FALSE; +} +void CGdiplusExt::GdipGetFontSize(void* pFont, FX_FLOAT* size) { + REAL get_size; + CGdiplusExt& GdiplusExt = + ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt; + GpStatus status = CallFunc(GdipGetFontSize)((GpFont*)pFont, (REAL*)&get_size); + if (status == Ok) { + *size = (FX_FLOAT)get_size; + } else { + *size = 0; + } +} +void CGdiplusExt::GdipSetTextRenderingHint(void* graphics, int mode) { + CGdiplusExt& GdiplusExt = + ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt; + CallFunc(GdipSetTextRenderingHint)((GpGraphics*)graphics, + (TextRenderingHint)mode); +} +void CGdiplusExt::GdipSetPageUnit(void* graphics, FX_DWORD unit) { + CGdiplusExt& GdiplusExt = + ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt; + CallFunc(GdipSetPageUnit)((GpGraphics*)graphics, (GpUnit)unit); +} +FX_BOOL CGdiplusExt::GdipDrawDriverString(void* graphics, + unsigned short* text, + int length, + void* font, + void* brush, + void* positions, + int flags, + const void* matrix) { + CGdiplusExt& GdiplusExt = + ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt; + GpStatus status = CallFunc(GdipDrawDriverString)( + (GpGraphics*)graphics, (GDIPCONST UINT16*)text, (INT)length, + (GDIPCONST GpFont*)font, (GDIPCONST GpBrush*)brush, + (GDIPCONST PointF*)positions, (INT)flags, (GDIPCONST GpMatrix*)matrix); + if (status == Ok) { + return TRUE; + } + return FALSE; +} +void CGdiplusExt::GdipCreateBrush(FX_DWORD fill_argb, void** pBrush) { + CGdiplusExt& GdiplusExt = + ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt; + CallFunc(GdipCreateSolidFill)((ARGB)fill_argb, (GpSolidFill**)pBrush); +} +void CGdiplusExt::GdipDeleteBrush(void* pBrush) { + CGdiplusExt& GdiplusExt = + ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt; + CallFunc(GdipDeleteBrush)((GpSolidFill*)pBrush); +} +void* CGdiplusExt::GdipCreateFontFromCollection(void* pFontCollection, + FX_FLOAT font_size, + int fontstyle) { + CGdiplusExt& GdiplusExt = + ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt; + int numFamilies = 0; + GpStatus status = CallFunc(GdipGetFontCollectionFamilyCount)( + (GpFontCollection*)pFontCollection, &numFamilies); + if (status != Ok) { + return NULL; + } + GpFontFamily* family_list[1]; + status = CallFunc(GdipGetFontCollectionFamilyList)( + (GpFontCollection*)pFontCollection, 1, family_list, &numFamilies); + if (status != Ok) { + return NULL; + } + GpFont* pFont = NULL; + status = CallFunc(GdipCreateFont)(family_list[0], font_size, fontstyle, + UnitPixel, &pFont); + if (status != Ok) { + return NULL; + } + return pFont; +} +void CGdiplusExt::GdipCreateMatrix(FX_FLOAT a, + FX_FLOAT b, + FX_FLOAT c, + FX_FLOAT d, + FX_FLOAT e, + FX_FLOAT f, + void** matrix) { + CGdiplusExt& GdiplusExt = + ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt; + CallFunc(GdipCreateMatrix2)(a, b, c, d, e, f, (GpMatrix**)matrix); +} +void CGdiplusExt::GdipDeleteMatrix(void* matrix) { + CGdiplusExt& GdiplusExt = + ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt; + CallFunc(GdipDeleteMatrix)((GpMatrix*)matrix); +} +void CGdiplusExt::GdipDeleteFontFamily(void* pFamily) { + CGdiplusExt& GdiplusExt = + ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt; + CallFunc(GdipDeleteFontFamily)((GpFontFamily*)pFamily); +} +void CGdiplusExt::GdipDeleteFont(void* pFont) { + CGdiplusExt& GdiplusExt = + ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt; + CallFunc(GdipDeleteFont)((GpFont*)pFont); +} +void CGdiplusExt::GdipSetWorldTransform(void* graphics, void* pMatrix) { + CGdiplusExt& GdiplusExt = + ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt; + CallFunc(GdipSetWorldTransform)((GpGraphics*)graphics, (GpMatrix*)pMatrix); +} +void CGdiplusExt::GdipDisposeImage(void* bitmap) { + CGdiplusExt& GdiplusExt = + ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt; + CallFunc(GdipDisposeImage)((GpBitmap*)bitmap); +} +void CGdiplusExt::GdipDeleteGraphics(void* graphics) { + CGdiplusExt& GdiplusExt = + ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt; + CallFunc(GdipDeleteGraphics)((GpGraphics*)graphics); +} +FX_BOOL CGdiplusExt::StretchBitMask(HDC hDC, + BOOL bMonoDevice, + const CFX_DIBitmap* pBitmap, + int dest_left, + int dest_top, + int dest_width, + int dest_height, + FX_DWORD argb, + const FX_RECT* pClipRect, + int flags) { + ASSERT(pBitmap->GetBPP() == 1); + CGdiplusExt& GdiplusExt = + ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt; + GpGraphics* pGraphics = NULL; + CallFunc(GdipCreateFromHDC)(hDC, &pGraphics); + CallFunc(GdipSetPageUnit)(pGraphics, UnitPixel); + if (flags & FXDIB_NOSMOOTH) { + CallFunc(GdipSetInterpolationMode)(pGraphics, + InterpolationModeNearestNeighbor); + } else { + CallFunc(GdipSetInterpolationMode)(pGraphics, InterpolationModeHighQuality); + } + OutputImageMask(pGraphics, bMonoDevice, pBitmap, dest_left, dest_top, + dest_width, dest_height, argb, pClipRect); + CallFunc(GdipDeleteGraphics)(pGraphics); + return TRUE; +} +FX_BOOL CGdiplusExt::StretchDIBits(HDC hDC, + const CFX_DIBitmap* pBitmap, + int dest_left, + int dest_top, + int dest_width, + int dest_height, + const FX_RECT* pClipRect, + int flags) { + GpGraphics* pGraphics; + CGdiplusExt& GdiplusExt = + ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt; + CallFunc(GdipCreateFromHDC)(hDC, &pGraphics); + CallFunc(GdipSetPageUnit)(pGraphics, UnitPixel); + if (flags & FXDIB_NOSMOOTH) { + CallFunc(GdipSetInterpolationMode)(pGraphics, + InterpolationModeNearestNeighbor); + } else if (pBitmap->GetWidth() > abs(dest_width) / 2 || + pBitmap->GetHeight() > abs(dest_height) / 2) { + CallFunc(GdipSetInterpolationMode)(pGraphics, InterpolationModeHighQuality); + } else { + CallFunc(GdipSetInterpolationMode)(pGraphics, InterpolationModeBilinear); + } + FX_RECT src_rect(0, 0, pBitmap->GetWidth(), pBitmap->GetHeight()); + OutputImage(pGraphics, pBitmap, &src_rect, dest_left, dest_top, dest_width, + dest_height); + CallFunc(GdipDeleteGraphics)(pGraphics); + CallFunc(GdipDeleteGraphics)(pGraphics); + return TRUE; +} +static GpPen* _GdipCreatePen(const CFX_GraphStateData* pGraphState, + const CFX_Matrix* pMatrix, + DWORD argb, + FX_BOOL bTextMode = FALSE) { + CGdiplusExt& GdiplusExt = + ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt; + FX_FLOAT width = pGraphState ? pGraphState->m_LineWidth : 1.0f; + if (!bTextMode) { + FX_FLOAT unit = + pMatrix ? 1.0f / ((pMatrix->GetXUnit() + pMatrix->GetYUnit()) / 2) + : 1.0f; + if (width < unit) { + width = unit; + } + } + GpPen* pPen = NULL; + CallFunc(GdipCreatePen1)((ARGB)argb, width, UnitWorld, &pPen); + LineCap lineCap; + DashCap dashCap = DashCapFlat; + FX_BOOL bDashExtend = FALSE; + switch (pGraphState->m_LineCap) { + case CFX_GraphStateData::LineCapButt: + lineCap = LineCapFlat; + break; + case CFX_GraphStateData::LineCapRound: + lineCap = LineCapRound; + dashCap = DashCapRound; + bDashExtend = TRUE; + break; + case CFX_GraphStateData::LineCapSquare: + lineCap = LineCapSquare; + bDashExtend = TRUE; + break; + } + CallFunc(GdipSetPenLineCap197819)(pPen, lineCap, lineCap, dashCap); + LineJoin lineJoin; + switch (pGraphState->m_LineJoin) { + case CFX_GraphStateData::LineJoinMiter: + lineJoin = LineJoinMiterClipped; + break; + case CFX_GraphStateData::LineJoinRound: + lineJoin = LineJoinRound; + break; + case CFX_GraphStateData::LineJoinBevel: + lineJoin = LineJoinBevel; + break; + } + CallFunc(GdipSetPenLineJoin)(pPen, lineJoin); + if (pGraphState->m_DashCount) { + FX_FLOAT* pDashArray = FX_Alloc( + FX_FLOAT, pGraphState->m_DashCount + pGraphState->m_DashCount % 2); + int nCount = 0; + FX_FLOAT on_leftover = 0, off_leftover = 0; + for (int i = 0; i < pGraphState->m_DashCount; i += 2) { + FX_FLOAT on_phase = pGraphState->m_DashArray[i]; + FX_FLOAT off_phase; + if (i == pGraphState->m_DashCount - 1) { + off_phase = on_phase; + } else { + off_phase = pGraphState->m_DashArray[i + 1]; + } + on_phase /= width; + off_phase /= width; + if (on_phase + off_phase <= 0.00002f) { + on_phase = 1.0f / 10; + off_phase = 1.0f / 10; + } + if (bDashExtend) { + if (off_phase < 1) { + off_phase = 0; + } else { + off_phase -= 1; + } + on_phase += 1; + } + if (on_phase == 0 || off_phase == 0) { + if (nCount == 0) { + on_leftover += on_phase; + off_leftover += off_phase; + } else { + pDashArray[nCount - 2] += on_phase; + pDashArray[nCount - 1] += off_phase; + } + } else { + pDashArray[nCount++] = on_phase + on_leftover; + on_leftover = 0; + pDashArray[nCount++] = off_phase + off_leftover; + off_leftover = 0; + } + } + CallFunc(GdipSetPenDashArray)(pPen, pDashArray, nCount); + FX_FLOAT phase = pGraphState->m_DashPhase; + if (bDashExtend) { + if (phase < 0.5f) { + phase = 0; + } else { + phase -= 0.5f; + } + } + CallFunc(GdipSetPenDashOffset)(pPen, phase); + FX_Free(pDashArray); + pDashArray = NULL; + } + CallFunc(GdipSetPenMiterLimit)(pPen, pGraphState->m_MiterLimit); + return pPen; +} +static FX_BOOL IsSmallTriangle(PointF* points, + const CFX_Matrix* pMatrix, + int& v1, + int& v2) { + int pairs[] = {1, 2, 0, 2, 0, 1}; + for (int i = 0; i < 3; i++) { + int pair1 = pairs[i * 2]; + int pair2 = pairs[i * 2 + 1]; + FX_FLOAT x1 = points[pair1].X, x2 = points[pair2].X; + FX_FLOAT y1 = points[pair1].Y, y2 = points[pair2].Y; + if (pMatrix) { + pMatrix->Transform(x1, y1); + pMatrix->Transform(x2, y2); + } + FX_FLOAT dx = x1 - x2; + FX_FLOAT dy = y1 - y2; + FX_FLOAT distance_square = (dx * dx) + (dy * dy); + if (distance_square < (1.0f * 2 + 1.0f / 4)) { + v1 = i; + v2 = pair1; + return TRUE; + } + } + return FALSE; +} +FX_BOOL CGdiplusExt::DrawPath(HDC hDC, + const CFX_PathData* pPathData, + const CFX_Matrix* pObject2Device, + const CFX_GraphStateData* pGraphState, + FX_DWORD fill_argb, + FX_DWORD stroke_argb, + int fill_mode) { + int nPoints = pPathData->GetPointCount(); + if (nPoints == 0) { + return TRUE; + } + FX_PATHPOINT* pPoints = pPathData->GetPoints(); + GpGraphics* pGraphics = NULL; + CGdiplusExt& GdiplusExt = + ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt; + CallFunc(GdipCreateFromHDC)(hDC, &pGraphics); + CallFunc(GdipSetPageUnit)(pGraphics, UnitPixel); + CallFunc(GdipSetPixelOffsetMode)(pGraphics, PixelOffsetModeHalf); + GpMatrix* pMatrix = NULL; + if (pObject2Device) { + CallFunc(GdipCreateMatrix2)(pObject2Device->a, pObject2Device->b, + pObject2Device->c, pObject2Device->d, + pObject2Device->e, pObject2Device->f, &pMatrix); + CallFunc(GdipSetWorldTransform)(pGraphics, pMatrix); + } + PointF* points = FX_Alloc(PointF, nPoints); + BYTE* types = FX_Alloc(BYTE, nPoints); + int nSubPathes = 0; + FX_BOOL bSubClose = FALSE; + int pos_subclose = 0; + FX_BOOL bSmooth = FALSE; + int startpoint = 0; + for (int i = 0; i < nPoints; i++) { + points[i].X = pPoints[i].m_PointX; + points[i].Y = pPoints[i].m_PointY; + FX_FLOAT x, y; + if (pObject2Device) { + pObject2Device->Transform(pPoints[i].m_PointX, pPoints[i].m_PointY, x, y); + } else { + x = pPoints[i].m_PointX; + y = pPoints[i].m_PointY; + } + if (x > 50000 * 1.0f) { + points[i].X = 50000 * 1.0f; + } + if (x < -50000 * 1.0f) { + points[i].X = -50000 * 1.0f; + } + if (y > 50000 * 1.0f) { + points[i].Y = 50000 * 1.0f; + } + if (y < -50000 * 1.0f) { + points[i].Y = -50000 * 1.0f; + } + int point_type = pPoints[i].m_Flag & FXPT_TYPE; + if (point_type == FXPT_MOVETO) { + types[i] = PathPointTypeStart; + nSubPathes++; + bSubClose = FALSE; + startpoint = i; + } else if (point_type == FXPT_LINETO) { + types[i] = PathPointTypeLine; + if (pPoints[i - 1].m_Flag == FXPT_MOVETO && + (i == nPoints - 1 || pPoints[i + 1].m_Flag == FXPT_MOVETO) && + points[i].Y == points[i - 1].Y && points[i].X == points[i - 1].X) { + points[i].X += 0.01f; + continue; + } + if (!bSmooth && points[i].X != points[i - 1].X && + points[i].Y != points[i - 1].Y) { + bSmooth = TRUE; + } + } else if (point_type == FXPT_BEZIERTO) { + types[i] = PathPointTypeBezier; + bSmooth = TRUE; + } + if (pPoints[i].m_Flag & FXPT_CLOSEFIGURE) { + if (bSubClose) { + types[pos_subclose] &= ~PathPointTypeCloseSubpath; + } else { + bSubClose = TRUE; + } + pos_subclose = i; + types[i] |= PathPointTypeCloseSubpath; + if (!bSmooth && points[i].X != points[startpoint].X && + points[i].Y != points[startpoint].Y) { + bSmooth = TRUE; + } + } + } + if (fill_mode & FXFILL_NOPATHSMOOTH) { + bSmooth = FALSE; + CallFunc(GdipSetSmoothingMode)(pGraphics, SmoothingModeNone); + } else if (!(fill_mode & FXFILL_FULLCOVER)) { + if (!bSmooth && (fill_mode & 3)) { + bSmooth = TRUE; + } + if (bSmooth || (pGraphState && pGraphState->m_LineWidth > 2)) { + CallFunc(GdipSetSmoothingMode)(pGraphics, SmoothingModeAntiAlias); + } + } + int new_fill_mode = fill_mode & 3; + if (nPoints == 4 && !pGraphState) { + int v1, v2; + if (IsSmallTriangle(points, pObject2Device, v1, v2)) { + GpPen* pPen = NULL; + CallFunc(GdipCreatePen1)(fill_argb, 1.0f, UnitPixel, &pPen); + CallFunc(GdipDrawLineI)( + pGraphics, pPen, FXSYS_round(points[v1].X), FXSYS_round(points[v1].Y), + FXSYS_round(points[v2].X), FXSYS_round(points[v2].Y)); + CallFunc(GdipDeletePen)(pPen); + return TRUE; + } + } + GpPath* pGpPath = NULL; + CallFunc(GdipCreatePath2)(points, types, nPoints, + GdiFillType2Gdip(new_fill_mode), &pGpPath); + if (!pGpPath) { + if (pMatrix) { + CallFunc(GdipDeleteMatrix)(pMatrix); + } + FX_Free(points); + FX_Free(types); + CallFunc(GdipDeleteGraphics)(pGraphics); + return FALSE; + } + if (new_fill_mode) { + GpBrush* pBrush = _GdipCreateBrush(fill_argb); + CallFunc(GdipSetPathFillMode)(pGpPath, GdiFillType2Gdip(new_fill_mode)); + CallFunc(GdipFillPath)(pGraphics, pBrush, pGpPath); + CallFunc(GdipDeleteBrush)(pBrush); + } + if (pGraphState && stroke_argb) { + GpPen* pPen = _GdipCreatePen(pGraphState, pObject2Device, stroke_argb, + fill_mode & FX_STROKE_TEXT_MODE); + if (nSubPathes == 1) { + CallFunc(GdipDrawPath)(pGraphics, pPen, pGpPath); + } else { + int iStart = 0; + for (int i = 0; i < nPoints; i++) { + if (i == nPoints - 1 || types[i + 1] == PathPointTypeStart) { + GpPath* pSubPath; + CallFunc(GdipCreatePath2)(points + iStart, types + iStart, + i - iStart + 1, + GdiFillType2Gdip(new_fill_mode), &pSubPath); + iStart = i + 1; + CallFunc(GdipDrawPath)(pGraphics, pPen, pSubPath); + CallFunc(GdipDeletePath)(pSubPath); + } + } + } + CallFunc(GdipDeletePen)(pPen); + } + if (pMatrix) { + CallFunc(GdipDeleteMatrix)(pMatrix); + } + FX_Free(points); + FX_Free(types); + CallFunc(GdipDeletePath)(pGpPath); + CallFunc(GdipDeleteGraphics)(pGraphics); + return TRUE; +} +class GpStream final : public IStream { + LONG m_RefCount; + int m_ReadPos; + CFX_ByteTextBuf m_InterStream; + + public: + GpStream() { + m_RefCount = 1; + m_ReadPos = 0; + } + virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, + void** ppvObject) { + if (iid == __uuidof(IUnknown) || iid == __uuidof(IStream) || + iid == __uuidof(ISequentialStream)) { + *ppvObject = static_cast<IStream*>(this); + AddRef(); + return S_OK; + } + return E_NOINTERFACE; + } + virtual ULONG STDMETHODCALLTYPE AddRef(void) { + return (ULONG)InterlockedIncrement(&m_RefCount); + } + virtual ULONG STDMETHODCALLTYPE Release(void) { + ULONG res = (ULONG)InterlockedDecrement(&m_RefCount); + if (res == 0) { + delete this; + } + return res; + } + + public: + virtual HRESULT STDMETHODCALLTYPE Read(void* Output, + ULONG cb, + ULONG* pcbRead) { + size_t bytes_left; + size_t bytes_out; + if (pcbRead) { + *pcbRead = 0; + } + if (m_ReadPos == m_InterStream.GetLength()) { + return HRESULT_FROM_WIN32(ERROR_END_OF_MEDIA); + } + bytes_left = m_InterStream.GetLength() - m_ReadPos; + bytes_out = std::min(pdfium::base::checked_cast<size_t>(cb), bytes_left); + FXSYS_memcpy(Output, m_InterStream.GetBuffer() + m_ReadPos, bytes_out); + m_ReadPos += (int32_t)bytes_out; + if (pcbRead) { + *pcbRead = (ULONG)bytes_out; + } + return S_OK; + } + virtual HRESULT STDMETHODCALLTYPE Write(void const* Input, + ULONG cb, + ULONG* pcbWritten) { + if (cb <= 0) { + if (pcbWritten) { + *pcbWritten = 0; + } + return S_OK; + } + m_InterStream.InsertBlock(m_InterStream.GetLength(), Input, cb); + if (pcbWritten) { + *pcbWritten = cb; + } + return S_OK; + } + + public: + virtual HRESULT STDMETHODCALLTYPE SetSize(ULARGE_INTEGER) { + return E_NOTIMPL; + } + virtual HRESULT STDMETHODCALLTYPE CopyTo(IStream*, + ULARGE_INTEGER, + ULARGE_INTEGER*, + ULARGE_INTEGER*) { + return E_NOTIMPL; + } + virtual HRESULT STDMETHODCALLTYPE Commit(DWORD) { return E_NOTIMPL; } + virtual HRESULT STDMETHODCALLTYPE Revert(void) { return E_NOTIMPL; } + virtual HRESULT STDMETHODCALLTYPE LockRegion(ULARGE_INTEGER, + ULARGE_INTEGER, + DWORD) { + return E_NOTIMPL; + } + virtual HRESULT STDMETHODCALLTYPE UnlockRegion(ULARGE_INTEGER, + ULARGE_INTEGER, + DWORD) { + return E_NOTIMPL; + } + virtual HRESULT STDMETHODCALLTYPE Clone(IStream** stream) { + return E_NOTIMPL; + } + virtual HRESULT STDMETHODCALLTYPE Seek(LARGE_INTEGER liDistanceToMove, + DWORD dwOrigin, + ULARGE_INTEGER* lpNewFilePointer) { + long start = 0; + long new_read_position; + switch (dwOrigin) { + case STREAM_SEEK_SET: + start = 0; + break; + case STREAM_SEEK_CUR: + start = m_ReadPos; + break; + case STREAM_SEEK_END: + start = m_InterStream.GetLength(); + break; + default: + return STG_E_INVALIDFUNCTION; + break; + } + new_read_position = start + (long)liDistanceToMove.QuadPart; + if (new_read_position < 0 || + new_read_position > m_InterStream.GetLength()) { + return STG_E_SEEKERROR; + } + m_ReadPos = new_read_position; + if (lpNewFilePointer) { + lpNewFilePointer->QuadPart = m_ReadPos; + } + return S_OK; + } + virtual HRESULT STDMETHODCALLTYPE Stat(STATSTG* pStatstg, DWORD grfStatFlag) { + if (!pStatstg) { + return STG_E_INVALIDFUNCTION; + } + ZeroMemory(pStatstg, sizeof(STATSTG)); + pStatstg->cbSize.QuadPart = m_InterStream.GetLength(); + return S_OK; + } +}; +typedef struct { + BITMAPINFO* pbmi; + int Stride; + LPBYTE pScan0; + GpBitmap* pBitmap; + BitmapData* pBitmapData; + GpStream* pStream; +} PREVIEW3_DIBITMAP; +static PREVIEW3_DIBITMAP* LoadDIBitmap(WINDIB_Open_Args_ args) { + GpBitmap* pBitmap; + GpStream* pStream = NULL; + CGdiplusExt& GdiplusExt = + ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt; + Status status = Ok; + if (args.flags == WINDIB_OPEN_PATHNAME) { + status = CallFunc(GdipCreateBitmapFromFileICM)((wchar_t*)args.path_name, + &pBitmap); + } else { + if (args.memory_size == 0 || !args.memory_base) { + return NULL; + } + pStream = new GpStream; + pStream->Write(args.memory_base, (ULONG)args.memory_size, NULL); + status = CallFunc(GdipCreateBitmapFromStreamICM)(pStream, &pBitmap); + } + if (status != Ok) { + if (pStream) { + pStream->Release(); + } + return NULL; + } + UINT height, width; + CallFunc(GdipGetImageHeight)(pBitmap, &height); + CallFunc(GdipGetImageWidth)(pBitmap, &width); + PixelFormat pixel_format; + CallFunc(GdipGetImagePixelFormat)(pBitmap, &pixel_format); + int info_size = sizeof(BITMAPINFOHEADER); + int bpp = 24; + int dest_pixel_format = PixelFormat24bppRGB; + if (pixel_format == PixelFormat1bppIndexed) { + info_size += 8; + bpp = 1; + dest_pixel_format = PixelFormat1bppIndexed; + } else if (pixel_format == PixelFormat8bppIndexed) { + info_size += 1024; + bpp = 8; + dest_pixel_format = PixelFormat8bppIndexed; + } else if (pixel_format == PixelFormat32bppARGB) { + bpp = 32; + dest_pixel_format = PixelFormat32bppARGB; + } + LPBYTE buf = FX_Alloc(BYTE, info_size); + BITMAPINFOHEADER* pbmih = (BITMAPINFOHEADER*)buf; + pbmih->biBitCount = bpp; + pbmih->biCompression = BI_RGB; + pbmih->biHeight = -(int)height; + pbmih->biPlanes = 1; + pbmih->biWidth = width; + Rect rect(0, 0, width, height); + BitmapData* pBitmapData = FX_Alloc(BitmapData, 1); + CallFunc(GdipBitmapLockBits)(pBitmap, &rect, ImageLockModeRead, + dest_pixel_format, pBitmapData); + if (pixel_format == PixelFormat1bppIndexed || + pixel_format == PixelFormat8bppIndexed) { + DWORD* ppal = (DWORD*)(buf + sizeof(BITMAPINFOHEADER)); + struct { + UINT flags; + UINT Count; + DWORD Entries[256]; + } pal; + int size = 0; + CallFunc(GdipGetImagePaletteSize)(pBitmap, &size); + CallFunc(GdipGetImagePalette)(pBitmap, (ColorPalette*)&pal, size); + int entries = pixel_format == PixelFormat1bppIndexed ? 2 : 256; + for (int i = 0; i < entries; i++) { + ppal[i] = pal.Entries[i] & 0x00ffffff; + } + } + PREVIEW3_DIBITMAP* pInfo = FX_Alloc(PREVIEW3_DIBITMAP, 1); + pInfo->pbmi = (BITMAPINFO*)buf; + pInfo->pScan0 = (LPBYTE)pBitmapData->Scan0; + pInfo->Stride = pBitmapData->Stride; + pInfo->pBitmap = pBitmap; + pInfo->pBitmapData = pBitmapData; + pInfo->pStream = pStream; + return pInfo; +} +static void FreeDIBitmap(PREVIEW3_DIBITMAP* pInfo) { + CGdiplusExt& GdiplusExt = + ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt; + CallFunc(GdipBitmapUnlockBits)(pInfo->pBitmap, pInfo->pBitmapData); + CallFunc(GdipDisposeImage)(pInfo->pBitmap); + FX_Free(pInfo->pBitmapData); + FX_Free((LPBYTE)pInfo->pbmi); + if (pInfo->pStream) { + pInfo->pStream->Release(); + } + FX_Free(pInfo); +} +CFX_DIBitmap* _FX_WindowsDIB_LoadFromBuf(BITMAPINFO* pbmi, + LPVOID pData, + FX_BOOL bAlpha); +CFX_DIBitmap* CGdiplusExt::LoadDIBitmap(WINDIB_Open_Args_ args) { + PREVIEW3_DIBITMAP* pInfo = ::LoadDIBitmap(args); + if (!pInfo) { + return NULL; + } + int height = abs(pInfo->pbmi->bmiHeader.biHeight); + int width = pInfo->pbmi->bmiHeader.biWidth; + int dest_pitch = (width * pInfo->pbmi->bmiHeader.biBitCount + 31) / 32 * 4; + LPBYTE pData = FX_Alloc2D(BYTE, dest_pitch, height); + if (dest_pitch == pInfo->Stride) { + FXSYS_memcpy(pData, pInfo->pScan0, dest_pitch * height); + } else { + for (int i = 0; i < height; i++) { + FXSYS_memcpy(pData + dest_pitch * i, pInfo->pScan0 + pInfo->Stride * i, + dest_pitch); + } + } + CFX_DIBitmap* pDIBitmap = _FX_WindowsDIB_LoadFromBuf( + pInfo->pbmi, pData, pInfo->pbmi->bmiHeader.biBitCount == 32); + FX_Free(pData); + FreeDIBitmap(pInfo); + return pDIBitmap; +} +#endif diff --git a/core/fxge/win32/fx_win32_print.cpp b/core/fxge/win32/fx_win32_print.cpp new file mode 100644 index 0000000000..c8529098eb --- /dev/null +++ b/core/fxge/win32/fx_win32_print.cpp @@ -0,0 +1,473 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "core/include/fxge/fx_ge.h" + +#if _FX_OS_ == _FX_WIN32_DESKTOP_ || _FX_OS_ == _FX_WIN64_DESKTOP_ + +#include <windows.h> + +#include "core/fxge/dib/dib_int.h" +#include "core/fxge/ge/fx_text_int.h" +#include "core/fxge/win32/win32_int.h" +#include "core/include/fxge/fx_freetype.h" +#include "core/include/fxge/fx_ge_win32.h" + +#define SIZETHRESHOLD 1000 +#define OUTPUTPSLEN 4096 +CGdiPrinterDriver::CGdiPrinterDriver(HDC hDC) + : CGdiDeviceDriver(hDC, FXDC_PRINTER) { + m_HorzSize = ::GetDeviceCaps(m_hDC, HORZSIZE); + m_VertSize = ::GetDeviceCaps(m_hDC, VERTSIZE); + m_bSupportROP = TRUE; +} +int CGdiPrinterDriver::GetDeviceCaps(int caps_id) { + if (caps_id == FXDC_HORZ_SIZE) { + return m_HorzSize; + } + if (caps_id == FXDC_VERT_SIZE) { + return m_VertSize; + } + return CGdiDeviceDriver::GetDeviceCaps(caps_id); +} +FX_BOOL CGdiPrinterDriver::SetDIBits(const CFX_DIBSource* pSource, + FX_DWORD color, + const FX_RECT* pSrcRect, + int left, + int top, + int blend_type, + int alpha_flag, + void* pIccTransform) { + if (pSource->IsAlphaMask()) { + FX_RECT clip_rect(left, top, left + pSrcRect->Width(), + top + pSrcRect->Height()); + return StretchDIBits(pSource, color, left - pSrcRect->left, + top - pSrcRect->top, pSource->GetWidth(), + pSource->GetHeight(), &clip_rect, 0, alpha_flag, + pIccTransform, FXDIB_BLEND_NORMAL); + } + ASSERT(pSource && !pSource->IsAlphaMask() && pSrcRect); + ASSERT(blend_type == FXDIB_BLEND_NORMAL); + if (pSource->HasAlpha()) { + return FALSE; + } + CFX_DIBExtractor temp(pSource); + CFX_DIBitmap* pBitmap = temp; + if (!pBitmap) { + return FALSE; + } + return GDI_SetDIBits(pBitmap, pSrcRect, left, top, pIccTransform); +} +FX_BOOL CGdiPrinterDriver::StretchDIBits(const CFX_DIBSource* pSource, + FX_DWORD color, + int dest_left, + int dest_top, + int dest_width, + int dest_height, + const FX_RECT* pClipRect, + FX_DWORD flags, + int alpha_flag, + void* pIccTransform, + int blend_type) { + if (pSource->IsAlphaMask()) { + int alpha = FXGETFLAG_COLORTYPE(alpha_flag) + ? FXGETFLAG_ALPHA_FILL(alpha_flag) + : FXARGB_A(color); + if (pSource->GetBPP() != 1 || alpha != 255 || !m_bSupportROP) { + return FALSE; + } + if (dest_width < 0 || dest_height < 0) { + CFX_DIBitmap* pFlipped = + pSource->FlipImage(dest_width < 0, dest_height < 0); + if (!pFlipped) { + return FALSE; + } + if (dest_width < 0) { + dest_left += dest_width; + } + if (dest_height < 0) { + dest_top += dest_height; + } + FX_BOOL ret = GDI_StretchBitMask(pFlipped, dest_left, dest_top, + abs(dest_width), abs(dest_height), color, + flags, alpha_flag, pIccTransform); + delete pFlipped; + return ret; + } + CFX_DIBExtractor temp(pSource); + CFX_DIBitmap* pBitmap = temp; + if (!pBitmap) { + return FALSE; + } + return GDI_StretchBitMask(pBitmap, dest_left, dest_top, dest_width, + dest_height, color, flags, alpha_flag, + pIccTransform); + } + if (pSource->HasAlpha()) { + return FALSE; + } + if (dest_width < 0 || dest_height < 0) { + CFX_DIBitmap* pFlipped = + pSource->FlipImage(dest_width < 0, dest_height < 0); + if (!pFlipped) { + return FALSE; + } + if (dest_width < 0) { + dest_left += dest_width; + } + if (dest_height < 0) { + dest_top += dest_height; + } + FX_BOOL ret = + GDI_StretchDIBits(pFlipped, dest_left, dest_top, abs(dest_width), + abs(dest_height), flags, pIccTransform); + delete pFlipped; + return ret; + } + CFX_DIBExtractor temp(pSource); + CFX_DIBitmap* pBitmap = temp; + if (!pBitmap) { + return FALSE; + } + return GDI_StretchDIBits(pBitmap, dest_left, dest_top, dest_width, + dest_height, flags, pIccTransform); +} +static CFX_DIBitmap* Transform1bppBitmap(const CFX_DIBSource* pSrc, + const CFX_Matrix* pDestMatrix) { + ASSERT(pSrc->GetFormat() == FXDIB_1bppRgb || + pSrc->GetFormat() == FXDIB_1bppMask || + pSrc->GetFormat() == FXDIB_1bppCmyk); + CFX_DIBExtractor src_bitmap(pSrc); + CFX_DIBitmap* pSrcBitmap = src_bitmap; + if (!pSrcBitmap) { + return NULL; + } + int src_width = pSrcBitmap->GetWidth(), src_height = pSrcBitmap->GetHeight(); + uint8_t* src_buf = pSrcBitmap->GetBuffer(); + FX_DWORD src_pitch = pSrcBitmap->GetPitch(); + FX_FLOAT dest_area = pDestMatrix->GetUnitArea(); + FX_FLOAT area_scale = ((FX_FLOAT)(src_width * src_height)) / dest_area; + FX_FLOAT size_scale = FXSYS_sqrt(area_scale); + CFX_Matrix adjusted_matrix(*pDestMatrix); + adjusted_matrix.Scale(size_scale, size_scale); + CFX_FloatRect result_rect_f = adjusted_matrix.GetUnitRect(); + FX_RECT result_rect = result_rect_f.GetOutterRect(); + CFX_Matrix src2result; + src2result.e = adjusted_matrix.c + adjusted_matrix.e; + src2result.f = adjusted_matrix.d + adjusted_matrix.f; + src2result.a = adjusted_matrix.a / pSrcBitmap->GetWidth(); + src2result.b = adjusted_matrix.b / pSrcBitmap->GetWidth(); + src2result.c = -adjusted_matrix.c / pSrcBitmap->GetHeight(); + src2result.d = -adjusted_matrix.d / pSrcBitmap->GetHeight(); + src2result.TranslateI(-result_rect.left, -result_rect.top); + CFX_Matrix result2src; + result2src.SetReverse(src2result); + CPDF_FixedMatrix result2src_fix(result2src, 8); + int result_width = result_rect.Width(); + int result_height = result_rect.Height(); + CFX_DIBitmap* pTempBitmap = new CFX_DIBitmap; + if (!pTempBitmap->Create(result_width, result_height, pSrc->GetFormat())) { + delete pTempBitmap; + if (pSrcBitmap != src_bitmap) { + delete pSrcBitmap; + } + return NULL; + } + pTempBitmap->CopyPalette(pSrc->GetPalette()); + uint8_t* dest_buf = pTempBitmap->GetBuffer(); + int dest_pitch = pTempBitmap->GetPitch(); + FXSYS_memset(dest_buf, pSrc->IsAlphaMask() ? 0 : 0xff, + dest_pitch * result_height); + if (pSrcBitmap->IsAlphaMask()) { + for (int dest_y = 0; dest_y < result_height; dest_y++) { + uint8_t* dest_scan = dest_buf + dest_y * dest_pitch; + for (int dest_x = 0; dest_x < result_width; dest_x++) { + int src_x, src_y; + result2src_fix.Transform(dest_x, dest_y, src_x, src_y); + if (src_x < 0 || src_x >= src_width || src_y < 0 || + src_y >= src_height) { + continue; + } + if (!((src_buf + src_pitch * src_y)[src_x / 8] & + (1 << (7 - src_x % 8)))) { + continue; + } + dest_scan[dest_x / 8] |= 1 << (7 - dest_x % 8); + } + } + } else { + for (int dest_y = 0; dest_y < result_height; dest_y++) { + uint8_t* dest_scan = dest_buf + dest_y * dest_pitch; + for (int dest_x = 0; dest_x < result_width; dest_x++) { + int src_x, src_y; + result2src_fix.Transform(dest_x, dest_y, src_x, src_y); + if (src_x < 0 || src_x >= src_width || src_y < 0 || + src_y >= src_height) { + continue; + } + if ((src_buf + src_pitch * src_y)[src_x / 8] & (1 << (7 - src_x % 8))) { + continue; + } + dest_scan[dest_x / 8] &= ~(1 << (7 - dest_x % 8)); + } + } + } + if (pSrcBitmap != src_bitmap) { + delete pSrcBitmap; + } + return pTempBitmap; +} +FX_BOOL CGdiPrinterDriver::StartDIBits(const CFX_DIBSource* pSource, + int bitmap_alpha, + FX_DWORD color, + const CFX_Matrix* pMatrix, + FX_DWORD render_flags, + void*& handle, + int alpha_flag, + void* pIccTransform, + int blend_type) { + if (bitmap_alpha < 255 || pSource->HasAlpha() || + (pSource->IsAlphaMask() && (pSource->GetBPP() != 1 || !m_bSupportROP))) { + return FALSE; + } + CFX_FloatRect unit_rect = pMatrix->GetUnitRect(); + FX_RECT full_rect = unit_rect.GetOutterRect(); + if (FXSYS_fabs(pMatrix->b) < 0.5f && pMatrix->a != 0 && + FXSYS_fabs(pMatrix->c) < 0.5f && pMatrix->d != 0) { + FX_BOOL bFlipX = pMatrix->a < 0; + FX_BOOL bFlipY = pMatrix->d > 0; + return StretchDIBits(pSource, color, + bFlipX ? full_rect.right : full_rect.left, + bFlipY ? full_rect.bottom : full_rect.top, + bFlipX ? -full_rect.Width() : full_rect.Width(), + bFlipY ? -full_rect.Height() : full_rect.Height(), + NULL, 0, alpha_flag, pIccTransform, blend_type); + } + if (FXSYS_fabs(pMatrix->a) < 0.5f && FXSYS_fabs(pMatrix->d) < 0.5f) { + CFX_DIBitmap* pTransformed = + pSource->SwapXY(pMatrix->c > 0, pMatrix->b < 0); + if (!pTransformed) { + return FALSE; + } + FX_BOOL ret = StretchDIBits( + pTransformed, color, full_rect.left, full_rect.top, full_rect.Width(), + full_rect.Height(), NULL, 0, alpha_flag, pIccTransform, blend_type); + delete pTransformed; + return ret; + } + if (pSource->GetBPP() == 1) { + CFX_DIBitmap* pTransformed = Transform1bppBitmap(pSource, pMatrix); + if (!pIccTransform) { + return FALSE; + } + SaveState(); + CFX_PathData path; + path.AppendRect(0, 0, 1.0f, 1.0f); + SetClip_PathFill(&path, pMatrix, WINDING); + FX_BOOL ret = StretchDIBits( + pTransformed, color, full_rect.left, full_rect.top, full_rect.Width(), + full_rect.Height(), NULL, 0, alpha_flag, pIccTransform, blend_type); + RestoreState(); + delete pTransformed; + handle = NULL; + return ret; + } + return FALSE; +} +CPSOutput::CPSOutput(HDC hDC) { + m_hDC = hDC; + m_pBuf = NULL; +} +CPSOutput::~CPSOutput() { + FX_Free(m_pBuf); +} +void CPSOutput::Init() { + m_pBuf = FX_Alloc(FX_CHAR, 1026); +} +void CPSOutput::OutputPS(const FX_CHAR* str, int len) { + if (len < 0) { + len = (int)FXSYS_strlen(str); + } + int sent_len = 0; + while (len > 0) { + int send_len = len > 1024 ? 1024 : len; + *(FX_WORD*)m_pBuf = send_len; + FXSYS_memcpy(m_pBuf + 2, str + sent_len, send_len); + ExtEscape(m_hDC, PASSTHROUGH, send_len + 2, m_pBuf, 0, NULL); + sent_len += send_len; + len -= send_len; + } +} +CPSPrinterDriver::CPSPrinterDriver() { + m_pPSOutput = NULL; + m_bCmykOutput = FALSE; +} +CPSPrinterDriver::~CPSPrinterDriver() { + EndRendering(); + delete m_pPSOutput; +} +FX_BOOL CPSPrinterDriver::Init(HDC hDC, int pslevel, FX_BOOL bCmykOutput) { + m_hDC = hDC; + m_HorzSize = ::GetDeviceCaps(m_hDC, HORZSIZE); + m_VertSize = ::GetDeviceCaps(m_hDC, VERTSIZE); + m_Width = ::GetDeviceCaps(m_hDC, HORZRES); + m_Height = ::GetDeviceCaps(m_hDC, VERTRES); + m_nBitsPerPixel = ::GetDeviceCaps(m_hDC, BITSPIXEL); + m_pPSOutput = new CPSOutput(hDC); + ((CPSOutput*)m_pPSOutput)->Init(); + m_PSRenderer.Init(m_pPSOutput, pslevel, m_Width, m_Height, bCmykOutput); + m_bCmykOutput = bCmykOutput; + HRGN hRgn = ::CreateRectRgn(0, 0, 1, 1); + int ret = ::GetClipRgn(hDC, hRgn); + if (ret == 1) { + ret = ::GetRegionData(hRgn, 0, NULL); + if (ret) { + RGNDATA* pData = (RGNDATA*)FX_Alloc(uint8_t, ret); + ret = ::GetRegionData(hRgn, ret, pData); + if (ret) { + CFX_PathData path; + path.AllocPointCount(pData->rdh.nCount * 5); + for (FX_DWORD i = 0; i < pData->rdh.nCount; i++) { + RECT* pRect = (RECT*)(pData->Buffer + pData->rdh.nRgnSize * i); + path.AppendRect((FX_FLOAT)pRect->left, (FX_FLOAT)pRect->bottom, + (FX_FLOAT)pRect->right, (FX_FLOAT)pRect->top); + } + m_PSRenderer.SetClip_PathFill(&path, NULL, FXFILL_WINDING); + } + FX_Free(pData); + } + } + ::DeleteObject(hRgn); + return TRUE; +} +int CPSPrinterDriver::GetDeviceCaps(int caps_id) { + switch (caps_id) { + case FXDC_DEVICE_CLASS: + return FXDC_PRINTER; + case FXDC_PIXEL_WIDTH: + return m_Width; + case FXDC_PIXEL_HEIGHT: + return m_Height; + case FXDC_BITS_PIXEL: + return m_nBitsPerPixel; + case FXDC_RENDER_CAPS: + return m_bCmykOutput ? FXRC_BIT_MASK | FXRC_CMYK_OUTPUT : FXRC_BIT_MASK; + case FXDC_HORZ_SIZE: + return m_HorzSize; + case FXDC_VERT_SIZE: + return m_VertSize; + } + return 0; +} +FX_BOOL CPSPrinterDriver::StartRendering() { + return m_PSRenderer.StartRendering(); +} +void CPSPrinterDriver::EndRendering() { + m_PSRenderer.EndRendering(); +} +void CPSPrinterDriver::SaveState() { + m_PSRenderer.SaveState(); +} +void CPSPrinterDriver::RestoreState(FX_BOOL bKeepSaved) { + m_PSRenderer.RestoreState(bKeepSaved); +} +FX_BOOL CPSPrinterDriver::SetClip_PathFill(const CFX_PathData* pPathData, + const CFX_Matrix* pObject2Device, + int fill_mode) { + m_PSRenderer.SetClip_PathFill(pPathData, pObject2Device, fill_mode); + return TRUE; +} +FX_BOOL CPSPrinterDriver::SetClip_PathStroke( + const CFX_PathData* pPathData, + const CFX_Matrix* pObject2Device, + const CFX_GraphStateData* pGraphState) { + m_PSRenderer.SetClip_PathStroke(pPathData, pObject2Device, pGraphState); + return TRUE; +} +FX_BOOL CPSPrinterDriver::DrawPath(const CFX_PathData* pPathData, + const CFX_Matrix* pObject2Device, + const CFX_GraphStateData* pGraphState, + FX_ARGB fill_color, + FX_ARGB stroke_color, + int fill_mode, + int alpha_flag, + void* pIccTransform, + int blend_type) { + if (blend_type != FXDIB_BLEND_NORMAL) { + return FALSE; + } + return m_PSRenderer.DrawPath(pPathData, pObject2Device, pGraphState, + fill_color, stroke_color, fill_mode & 3, + alpha_flag, pIccTransform); +} +FX_BOOL CPSPrinterDriver::GetClipBox(FX_RECT* pRect) { + *pRect = m_PSRenderer.GetClipBox(); + return TRUE; +} +FX_BOOL CPSPrinterDriver::SetDIBits(const CFX_DIBSource* pBitmap, + FX_DWORD color, + const FX_RECT* pSrcRect, + int left, + int top, + int blend_type, + int alpha_flag, + void* pIccTransform) { + if (blend_type != FXDIB_BLEND_NORMAL) { + return FALSE; + } + return m_PSRenderer.SetDIBits(pBitmap, color, left, top, alpha_flag, + pIccTransform); +} +FX_BOOL CPSPrinterDriver::StretchDIBits(const CFX_DIBSource* pBitmap, + FX_DWORD color, + int dest_left, + int dest_top, + int dest_width, + int dest_height, + const FX_RECT* pClipRect, + FX_DWORD flags, + int alpha_flag, + void* pIccTransform, + int blend_type) { + if (blend_type != FXDIB_BLEND_NORMAL) { + return FALSE; + } + return m_PSRenderer.StretchDIBits(pBitmap, color, dest_left, dest_top, + dest_width, dest_height, flags, alpha_flag, + pIccTransform); +} +FX_BOOL CPSPrinterDriver::StartDIBits(const CFX_DIBSource* pBitmap, + int bitmap_alpha, + FX_DWORD color, + const CFX_Matrix* pMatrix, + FX_DWORD render_flags, + void*& handle, + int alpha_flag, + void* pIccTransform, + int blend_type) { + if (blend_type != FXDIB_BLEND_NORMAL) { + return FALSE; + } + if (bitmap_alpha < 255) { + return FALSE; + } + handle = NULL; + return m_PSRenderer.DrawDIBits(pBitmap, color, pMatrix, render_flags, + alpha_flag, pIccTransform); +} +FX_BOOL CPSPrinterDriver::DrawDeviceText(int nChars, + const FXTEXT_CHARPOS* pCharPos, + CFX_Font* pFont, + CFX_FontCache* pCache, + const CFX_Matrix* pObject2Device, + FX_FLOAT font_size, + FX_DWORD color, + int alpha_flag, + void* pIccTransform) { + return m_PSRenderer.DrawText(nChars, pCharPos, pFont, pCache, pObject2Device, + font_size, color, alpha_flag, pIccTransform); +} +#endif diff --git a/core/fxge/win32/win32_int.h b/core/fxge/win32/win32_int.h new file mode 100644 index 0000000000..bdba9547b3 --- /dev/null +++ b/core/fxge/win32/win32_int.h @@ -0,0 +1,369 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#ifndef CORE_FXGE_WIN32_WIN32_INT_H_ +#define CORE_FXGE_WIN32_WIN32_INT_H_ + +#include "core/fxge/win32/dwrite_int.h" +#include "core/include/fxge/fx_ge.h" + +struct WINDIB_Open_Args_; +class CGdiplusExt { + public: + CGdiplusExt(); + ~CGdiplusExt(); + void Load(); + FX_BOOL IsAvailable() { return m_hModule != NULL; } + FX_BOOL StretchBitMask(HDC hDC, + BOOL bMonoDevice, + const CFX_DIBitmap* pBitmap, + int dest_left, + int dest_top, + int dest_width, + int dest_height, + FX_DWORD argb, + const FX_RECT* pClipRect, + int flags); + FX_BOOL StretchDIBits(HDC hDC, + const CFX_DIBitmap* pBitmap, + int dest_left, + int dest_top, + int dest_width, + int dest_height, + const FX_RECT* pClipRect, + int flags); + FX_BOOL DrawPath(HDC hDC, + const CFX_PathData* pPathData, + const CFX_Matrix* pObject2Device, + const CFX_GraphStateData* pGraphState, + FX_DWORD fill_argb, + FX_DWORD stroke_argb, + int fill_mode); + + void* LoadMemFont(uint8_t* pData, FX_DWORD size); + void DeleteMemFont(void* pFontCollection); + FX_BOOL GdipCreateFromImage(void* bitmap, void** graphics); + void GdipDeleteGraphics(void* graphics); + void GdipSetTextRenderingHint(void* graphics, int mode); + void GdipSetPageUnit(void* graphics, FX_DWORD unit); + void GdipSetWorldTransform(void* graphics, void* pMatrix); + FX_BOOL GdipDrawDriverString(void* graphics, + unsigned short* text, + int length, + void* font, + void* brush, + void* positions, + int flags, + const void* matrix); + void GdipCreateBrush(FX_DWORD fill_argb, void** pBrush); + void GdipDeleteBrush(void* pBrush); + void GdipCreateMatrix(FX_FLOAT a, + FX_FLOAT b, + FX_FLOAT c, + FX_FLOAT d, + FX_FLOAT e, + FX_FLOAT f, + void** matrix); + void GdipDeleteMatrix(void* matrix); + FX_BOOL GdipCreateFontFamilyFromName(const FX_WCHAR* name, + void* pFontCollection, + void** pFamily); + void GdipDeleteFontFamily(void* pFamily); + FX_BOOL GdipCreateFontFromFamily(void* pFamily, + FX_FLOAT font_size, + int fontstyle, + int flag, + void** pFont); + void* GdipCreateFontFromCollection(void* pFontCollection, + FX_FLOAT font_size, + int fontstyle); + void GdipDeleteFont(void* pFont); + FX_BOOL GdipCreateBitmap(CFX_DIBitmap* pBitmap, void** bitmap); + void GdipDisposeImage(void* bitmap); + void GdipGetFontSize(void* pFont, FX_FLOAT* size); + void* GdiAddFontMemResourceEx(void* pFontdata, + FX_DWORD size, + void* pdv, + FX_DWORD* num_face); + FX_BOOL GdiRemoveFontMemResourceEx(void* handle); + void* m_Functions[100]; + void* m_pGdiAddFontMemResourceEx; + void* m_pGdiRemoveFontMemResourseEx; + CFX_DIBitmap* LoadDIBitmap(WINDIB_Open_Args_ args); + + protected: + HMODULE m_hModule; + HMODULE m_GdiModule; +}; +class CWin32Platform { + public: + FX_BOOL m_bHalfTone; + CGdiplusExt m_GdiplusExt; + CDWriteExt m_DWriteExt; +}; + +class CGdiDeviceDriver : public IFX_RenderDeviceDriver { + protected: + // IFX_RenderDeviceDriver + int GetDeviceCaps(int caps_id) override; + void SaveState() override { SaveDC(m_hDC); } + void RestoreState(FX_BOOL bKeepSaved = FALSE) override { + RestoreDC(m_hDC, -1); + if (bKeepSaved) { + SaveDC(m_hDC); + } + } + FX_BOOL SetClip_PathFill(const CFX_PathData* pPathData, + const CFX_Matrix* pObject2Device, + int fill_mode) override; + FX_BOOL SetClip_PathStroke(const CFX_PathData* pPathData, + const CFX_Matrix* pObject2Device, + const CFX_GraphStateData* pGraphState) override; + FX_BOOL DrawPath(const CFX_PathData* pPathData, + const CFX_Matrix* pObject2Device, + const CFX_GraphStateData* pGraphState, + FX_DWORD fill_color, + FX_DWORD stroke_color, + int fill_mode, + int alpha_flag, + void* pIccTransform, + int blend_type) override; + FX_BOOL FillRect(const FX_RECT* pRect, + FX_DWORD fill_color, + int alpha_flag, + void* pIccTransform, + int blend_type) override; + FX_BOOL DrawCosmeticLine(FX_FLOAT x1, + FX_FLOAT y1, + FX_FLOAT x2, + FX_FLOAT y2, + FX_DWORD color, + int alpha_flag, + void* pIccTransform, + int blend_type) override; + FX_BOOL GetClipBox(FX_RECT* pRect) override; + void* GetPlatformSurface() override { return (void*)m_hDC; } + + virtual void* GetClipRgn(); + virtual FX_BOOL SetClipRgn(void* pRgn); + virtual FX_BOOL DeleteDeviceRgn(void* pRgn); + virtual void DrawLine(FX_FLOAT x1, FX_FLOAT y1, FX_FLOAT x2, FX_FLOAT y2); + + FX_BOOL GDI_SetDIBits(const CFX_DIBitmap* pBitmap, + const FX_RECT* pSrcRect, + int left, + int top, + void* pIccTransform); + FX_BOOL GDI_StretchDIBits(const CFX_DIBitmap* pBitmap, + int dest_left, + int dest_top, + int dest_width, + int dest_height, + FX_DWORD flags, + void* pIccTransform); + FX_BOOL GDI_StretchBitMask(const CFX_DIBitmap* pBitmap, + int dest_left, + int dest_top, + int dest_width, + int dest_height, + FX_DWORD bitmap_color, + FX_DWORD flags, + int alpha_flag, + void* pIccTransform); + HDC m_hDC; + int m_Width, m_Height, m_nBitsPerPixel; + int m_DeviceClass, m_RenderCaps; + CGdiDeviceDriver(HDC hDC, int device_class); + ~CGdiDeviceDriver() override {} +}; + +class CGdiDisplayDriver : public CGdiDeviceDriver { + public: + CGdiDisplayDriver(HDC hDC); + + protected: + virtual FX_BOOL GetDIBits(CFX_DIBitmap* pBitmap, + int left, + int top, + void* pIccTransform = NULL, + FX_BOOL bDEdge = FALSE); + virtual FX_BOOL SetDIBits(const CFX_DIBSource* pBitmap, + FX_DWORD color, + const FX_RECT* pSrcRect, + int left, + int top, + int blend_type, + int alpha_flag, + void* pIccTransform); + virtual FX_BOOL StretchDIBits(const CFX_DIBSource* pBitmap, + FX_DWORD color, + int dest_left, + int dest_top, + int dest_width, + int dest_height, + const FX_RECT* pClipRect, + FX_DWORD flags, + int alpha_flag, + void* pIccTransform, + int blend_type); + virtual FX_BOOL StartDIBits(const CFX_DIBSource* pBitmap, + int bitmap_alpha, + FX_DWORD color, + const CFX_Matrix* pMatrix, + FX_DWORD render_flags, + void*& handle, + int alpha_flag, + void* pIccTransform, + int blend_type) { + return FALSE; + } + FX_BOOL UseFoxitStretchEngine(const CFX_DIBSource* pSource, + FX_DWORD color, + int dest_left, + int dest_top, + int dest_width, + int dest_height, + const FX_RECT* pClipRect, + int render_flags, + int alpha_flag = 0, + void* pIccTransform = NULL, + int blend_type = FXDIB_BLEND_NORMAL); +}; +class CGdiPrinterDriver : public CGdiDeviceDriver { + public: + CGdiPrinterDriver(HDC hDC); + + protected: + virtual int GetDeviceCaps(int caps_id); + virtual FX_BOOL SetDIBits(const CFX_DIBSource* pBitmap, + FX_DWORD color, + const FX_RECT* pSrcRect, + int left, + int top, + int blend_type, + int alpha_flag, + void* pIccTransform); + virtual FX_BOOL StretchDIBits(const CFX_DIBSource* pBitmap, + FX_DWORD color, + int dest_left, + int dest_top, + int dest_width, + int dest_height, + const FX_RECT* pClipRect, + FX_DWORD flags, + int alpha_flag, + void* pIccTransform, + int blend_type); + virtual FX_BOOL StartDIBits(const CFX_DIBSource* pBitmap, + int bitmap_alpha, + FX_DWORD color, + const CFX_Matrix* pMatrix, + FX_DWORD render_flags, + void*& handle, + int alpha_flag, + void* pIccTransform, + int blend_type); + int m_HorzSize, m_VertSize; + FX_BOOL m_bSupportROP; +}; + +class CPSOutput : public IFX_PSOutput { + public: + explicit CPSOutput(HDC hDC); + ~CPSOutput() override; + + // IFX_PSOutput + void Release() override { delete this; } + void OutputPS(const FX_CHAR* str, int len) override; + + void Init(); + + HDC m_hDC; + FX_CHAR* m_pBuf; +}; + +class CPSPrinterDriver : public IFX_RenderDeviceDriver { + public: + CPSPrinterDriver(); + FX_BOOL Init(HDC hDC, int ps_level, FX_BOOL bCmykOutput); + ~CPSPrinterDriver() override; + + protected: + // IFX_RenderDeviceDriver + int GetDeviceCaps(int caps_id); + FX_BOOL IsPSPrintDriver() override { return TRUE; } + FX_BOOL StartRendering() override; + void EndRendering() override; + void SaveState() override; + void RestoreState(FX_BOOL bKeepSaved = FALSE) override; + FX_BOOL SetClip_PathFill(const CFX_PathData* pPathData, + const CFX_Matrix* pObject2Device, + int fill_mode) override; + FX_BOOL SetClip_PathStroke(const CFX_PathData* pPathData, + const CFX_Matrix* pObject2Device, + const CFX_GraphStateData* pGraphState) override; + FX_BOOL DrawPath(const CFX_PathData* pPathData, + const CFX_Matrix* pObject2Device, + const CFX_GraphStateData* pGraphState, + FX_DWORD fill_color, + FX_DWORD stroke_color, + int fill_mode, + int alpha_flag, + void* pIccTransform, + int blend_type) override; + FX_BOOL GetClipBox(FX_RECT* pRect) override; + FX_BOOL SetDIBits(const CFX_DIBSource* pBitmap, + FX_DWORD color, + const FX_RECT* pSrcRect, + int left, + int top, + int blend_type, + int alpha_flag, + void* pIccTransform) override; + FX_BOOL StretchDIBits(const CFX_DIBSource* pBitmap, + FX_DWORD color, + int dest_left, + int dest_top, + int dest_width, + int dest_height, + const FX_RECT* pClipRect, + FX_DWORD flags, + int alpha_flag, + void* pIccTransform, + int blend_type) override; + FX_BOOL StartDIBits(const CFX_DIBSource* pBitmap, + int bitmap_alpha, + FX_DWORD color, + const CFX_Matrix* pMatrix, + FX_DWORD render_flags, + void*& handle, + int alpha_flag, + void* pIccTransform, + int blend_type) override; + FX_BOOL DrawDeviceText(int nChars, + const FXTEXT_CHARPOS* pCharPos, + CFX_Font* pFont, + CFX_FontCache* pCache, + const CFX_Matrix* pObject2Device, + FX_FLOAT font_size, + FX_DWORD color, + int alpha_flag, + void* pIccTransform) override; + void* GetPlatformSurface() override { return (void*)m_hDC; } + + HDC m_hDC; + FX_BOOL m_bCmykOutput; + int m_Width, m_Height, m_nBitsPerPixel; + int m_HorzSize, m_VertSize; + CPSOutput* m_pPSOutput; + CFX_PSRenderer m_PSRenderer; +}; +void _Color2Argb(FX_ARGB& argb, + FX_DWORD color, + int alpha_flag, + void* pIccTransform); + +#endif // CORE_FXGE_WIN32_WIN32_INT_H_ |