From acbef05aa0dbceabf47d700968ccd6569524fe74 Mon Sep 17 00:00:00 2001 From: Lei Zhang Date: Tue, 30 Jan 2018 18:28:40 +0000 Subject: Use anonymous namespace in gdiplus code. Fix some nits as well. Change-Id: Ia52f4550c39d8072004679d764243ca9a9f7db0d Reviewed-on: https://pdfium-review.googlesource.com/24190 Reviewed-by: dsinclair Commit-Queue: Lei Zhang --- core/fxge/win32/fx_win32_dib.cpp | 8 +- core/fxge/win32/fx_win32_gdipext.cpp | 980 ++++++++++++++++++----------------- core/fxge/win32/win32_int.h | 3 + 3 files changed, 499 insertions(+), 492 deletions(-) diff --git a/core/fxge/win32/fx_win32_dib.cpp b/core/fxge/win32/fx_win32_dib.cpp index 6416b5af36..452d033f64 100644 --- a/core/fxge/win32/fx_win32_dib.cpp +++ b/core/fxge/win32/fx_win32_dib.cpp @@ -52,9 +52,9 @@ ByteString CFX_WindowsDIB::GetBitmapInfo( return result; } -RetainPtr _FX_WindowsDIB_LoadFromBuf(BITMAPINFO* pbmi, - LPVOID pData, - bool bAlpha) { +RetainPtr FX_WindowsDIB_LoadFromBuf(BITMAPINFO* pbmi, + LPVOID pData, + bool bAlpha) { int width = pbmi->bmiHeader.biWidth; int height = pbmi->bmiHeader.biHeight; BOOL bBottomUp = true; @@ -97,7 +97,7 @@ RetainPtr _FX_WindowsDIB_LoadFromBuf(BITMAPINFO* pbmi, RetainPtr CFX_WindowsDIB::LoadFromBuf(BITMAPINFO* pbmi, LPVOID pData) { - return _FX_WindowsDIB_LoadFromBuf(pbmi, pData, false); + return FX_WindowsDIB_LoadFromBuf(pbmi, pData, false); } HBITMAP CFX_WindowsDIB::GetDDBitmap(const RetainPtr& pBitmap, diff --git a/core/fxge/win32/fx_win32_gdipext.cpp b/core/fxge/win32/fx_win32_gdipext.cpp index a617036ea7..d784a0fa37 100644 --- a/core/fxge/win32/fx_win32_gdipext.cpp +++ b/core/fxge/win32/fx_win32_gdipext.cpp @@ -89,6 +89,8 @@ using Gdiplus::UnitWorld; #define GdiFillType2Gdip(fill_type) \ (fill_type == ALTERNATE ? FillModeAlternate : FillModeWinding) +namespace { + enum { FuncId_GdipCreatePath2, FuncId_GdipSetPenDashStyle, @@ -170,7 +172,7 @@ enum { FuncId_GdipSetPenTransform, }; -static LPCSTR g_GdipFuncNames[] = { +LPCSTR g_GdipFuncNames[] = { "GdipCreatePath2", "GdipSetPenDashStyle", "GdipSetPenDashArray", @@ -500,23 +502,7 @@ typedef GpStatus(WINGDIPAPI* FuncType_GdipSetPenTransform)(GpPen* pen, #define CallFunc(funcname) \ ((FuncType_##funcname)GdiplusExt.m_Functions[FuncId_##funcname]) -void* CGdiplusExt::GdiAddFontMemResourceEx(void* pFontdata, - uint32_t size, - void* pdv, - uint32_t* num_face) { - if (!m_pGdiAddFontMemResourceEx) - return nullptr; - - return m_pGdiAddFontMemResourceEx((PVOID)pFontdata, (DWORD)size, (PVOID)pdv, - (DWORD*)num_face); -} - -bool CGdiplusExt::GdiRemoveFontMemResourceEx(void* handle) { - return m_pGdiRemoveFontMemResourseEx && - m_pGdiRemoveFontMemResourseEx((HANDLE)handle); -} - -static GpBrush* _GdipCreateBrush(DWORD argb) { +GpBrush* GdipCreateBrushImpl(DWORD argb) { CGdiplusExt& GdiplusExt = ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt; GpSolidFill* solidBrush = nullptr; @@ -524,7 +510,7 @@ static GpBrush* _GdipCreateBrush(DWORD argb) { return solidBrush; } -static RetainPtr StretchMonoToGray( +RetainPtr StretchMonoToGray( int dest_width, int dest_height, const RetainPtr& pSource, @@ -579,15 +565,15 @@ static RetainPtr StretchMonoToGray( return pStretched; } -static void OutputImageMask(GpGraphics* pGraphics, - BOOL bMonoDevice, - const RetainPtr& pBitmap, - int dest_left, - int dest_top, - int dest_width, - int dest_height, - FX_ARGB argb, - const FX_RECT* pClipRect) { +void OutputImageMask(GpGraphics* pGraphics, + BOOL bMonoDevice, + const RetainPtr& 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; @@ -668,13 +654,14 @@ static void OutputImageMask(GpGraphics* pGraphics, CallFunc(GdipDrawImagePointsI)(pGraphics, bitmap, destinationPoints, 3); CallFunc(GdipDisposeImage)(bitmap); } -static void OutputImage(GpGraphics* pGraphics, - const RetainPtr& pBitmap, - const FX_RECT* pSrcRect, - int dest_left, - int dest_top, - int dest_width, - int dest_height) { + +void OutputImage(GpGraphics* pGraphics, + const RetainPtr& 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; @@ -737,98 +724,477 @@ static void OutputImage(GpGraphics* pGraphics, CallFunc(GdipDisposeImage)(bitmap); } -CGdiplusExt::CGdiplusExt() {} +GpPen* GdipCreatePenImpl(const CFX_GraphStateData* pGraphState, + const CFX_Matrix* pMatrix, + DWORD argb, + bool bTextMode) { + CGdiplusExt& GdiplusExt = + ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt; + float width = pGraphState ? pGraphState->m_LineWidth : 1.0f; + if (!bTextMode) { + float unit = pMatrix + ? 1.0f / ((pMatrix->GetXUnit() + pMatrix->GetYUnit()) / 2) + : 1.0f; + if (width < unit) + width = unit; + } + GpPen* pPen = nullptr; + CallFunc(GdipCreatePen1)((Gdiplus::ARGB)argb, width, UnitWorld, &pPen); + LineCap lineCap = LineCapFlat; + DashCap dashCap = DashCapFlat; + 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 = LineJoinMiterClipped; + 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) { + float* pDashArray = FX_Alloc( + float, pGraphState->m_DashCount + pGraphState->m_DashCount % 2); + int nCount = 0; + float on_leftover = 0, off_leftover = 0; + for (int i = 0; i < pGraphState->m_DashCount; i += 2) { + float on_phase = pGraphState->m_DashArray[i]; + 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); + 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 = nullptr; + } + CallFunc(GdipSetPenMiterLimit)(pPen, pGraphState->m_MiterLimit); + return pPen; +} -CGdiplusExt::~CGdiplusExt() { - FreeLibrary(m_GdiModule); - FreeLibrary(m_hModule); +bool IsSmallTriangle(Gdiplus::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]; + + CFX_PointF p1(points[pair1].X, points[pair1].Y); + CFX_PointF p2(points[pair2].X, points[pair2].Y); + if (pMatrix) { + p1 = pMatrix->Transform(p1); + p2 = pMatrix->Transform(p2); + } + + CFX_PointF diff = p1 - p2; + float distance_square = (diff.x * diff.x) + (diff.y * diff.y); + if (distance_square < (1.0f * 2 + 1.0f / 4)) { + v1 = i; + v2 = pair1; + return true; + } + } + return false; } -void CGdiplusExt::Load() { - char buf[MAX_PATH]; - GetSystemDirectoryA(buf, MAX_PATH); - ByteString dllpath = buf; - dllpath += "\\GDIPLUS.DLL"; - m_hModule = LoadLibraryA(dllpath.c_str()); - if (!m_hModule) - return; +class GpStream final : public IStream { + public: + GpStream() : m_RefCount(1), m_ReadPos(0) {} + ~GpStream() = default; - m_Functions.resize(FX_ArraySize(g_GdipFuncNames)); - for (size_t i = 0; i < FX_ArraySize(g_GdipFuncNames); ++i) { - m_Functions[i] = GetProcAddress(m_hModule, g_GdipFuncNames[i]); - if (!m_Functions[i]) { - m_hModule = nullptr; - return; + // IUnknown + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, + void** ppvObject) override { + if (iid == __uuidof(IUnknown) || iid == __uuidof(IStream) || + iid == __uuidof(ISequentialStream)) { + *ppvObject = static_cast(this); + AddRef(); + return S_OK; + } + return E_NOINTERFACE; + } + ULONG STDMETHODCALLTYPE AddRef() override { + return (ULONG)InterlockedIncrement(&m_RefCount); + } + ULONG STDMETHODCALLTYPE Release() override { + ULONG res = (ULONG)InterlockedDecrement(&m_RefCount); + if (res == 0) { + delete this; } + return res; } - uintptr_t gdiplusToken; - GdiplusStartupInput gdiplusStartupInput; - ((FuncType_GdiplusStartup)m_Functions[FuncId_GdiplusStartup])( - &gdiplusToken, &gdiplusStartupInput, nullptr); - m_GdiModule = LoadLibraryA("GDI32.DLL"); - if (!m_GdiModule) - return; + // ISequentialStream + HRESULT STDMETHODCALLTYPE Read(void* output, + ULONG cb, + ULONG* pcbRead) override { + if (pcbRead) + *pcbRead = 0; - m_pGdiAddFontMemResourceEx = - reinterpret_cast( - GetProcAddress(m_GdiModule, "AddFontMemResourceEx")); - m_pGdiRemoveFontMemResourseEx = - reinterpret_cast( - GetProcAddress(m_GdiModule, "RemoveFontMemResourceEx")); -} + if (m_ReadPos >= m_InterStream.tellp()) + return HRESULT_FROM_WIN32(ERROR_END_OF_MEDIA); -LPVOID CGdiplusExt::LoadMemFont(LPBYTE pData, uint32_t size) { - GpFontCollection* pCollection = nullptr; - CGdiplusExt& GdiplusExt = - ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt; - CallFunc(GdipNewPrivateFontCollection)(&pCollection); - GpStatus status = - CallFunc(GdipPrivateAddMemoryFont)(pCollection, pData, size); - if (status == Gdiplus::Ok) - return pCollection; + size_t bytes_left = m_InterStream.tellp() - m_ReadPos; + size_t bytes_out = + std::min(pdfium::base::checked_cast(cb), bytes_left); + memcpy(output, m_InterStream.str().c_str() + m_ReadPos, bytes_out); + m_ReadPos += bytes_out; + if (pcbRead) + *pcbRead = (ULONG)bytes_out; - CallFunc(GdipDeletePrivateFontCollection)(&pCollection); - return nullptr; -} -void CGdiplusExt::DeleteMemFont(LPVOID pCollection) { - CGdiplusExt& GdiplusExt = - ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt; - CallFunc(GdipDeletePrivateFontCollection)((GpFontCollection**)&pCollection); -} -bool CGdiplusExt::GdipCreateBitmap(const RetainPtr& pBitmap, - void** bitmap) { - CGdiplusExt& GdiplusExt = - ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt; - Gdiplus::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; + return S_OK; } - GpStatus status = CallFunc(GdipCreateBitmapFromScan0)( - pBitmap->GetWidth(), pBitmap->GetHeight(), pBitmap->GetPitch(), format, - pBitmap->GetBuffer(), (GpBitmap**)bitmap); - return status == Gdiplus::Ok; -} -bool CGdiplusExt::GdipCreateFromImage(void* bitmap, void** graphics) { - CGdiplusExt& GdiplusExt = - ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt; - GpStatus status = CallFunc(GdipGetImageGraphicsContext)( - (GpBitmap*)bitmap, (GpGraphics**)graphics); - return status == Gdiplus::Ok; -} -bool CGdiplusExt::GdipCreateFontFamilyFromName(const wchar_t* name, - void* pFontCollection, - void** pFamily) { + HRESULT STDMETHODCALLTYPE Write(const void* input, + ULONG cb, + ULONG* pcbWritten) override { + if (cb <= 0) { + if (pcbWritten) + *pcbWritten = 0; + return S_OK; + } + m_InterStream.write(reinterpret_cast(input), cb); + if (pcbWritten) + *pcbWritten = cb; + return S_OK; + } + + // IStream + HRESULT STDMETHODCALLTYPE SetSize(ULARGE_INTEGER) override { + return E_NOTIMPL; + } + HRESULT STDMETHODCALLTYPE CopyTo(IStream*, + ULARGE_INTEGER, + ULARGE_INTEGER*, + ULARGE_INTEGER*) override { + return E_NOTIMPL; + } + HRESULT STDMETHODCALLTYPE Commit(DWORD) override { return E_NOTIMPL; } + HRESULT STDMETHODCALLTYPE Revert() override { return E_NOTIMPL; } + HRESULT STDMETHODCALLTYPE LockRegion(ULARGE_INTEGER, + ULARGE_INTEGER, + DWORD) override { + return E_NOTIMPL; + } + HRESULT STDMETHODCALLTYPE UnlockRegion(ULARGE_INTEGER, + ULARGE_INTEGER, + DWORD) override { + return E_NOTIMPL; + } + HRESULT STDMETHODCALLTYPE Clone(IStream** stream) override { + return E_NOTIMPL; + } + HRESULT STDMETHODCALLTYPE Seek(LARGE_INTEGER liDistanceToMove, + DWORD dwOrigin, + ULARGE_INTEGER* lpNewFilePointer) override { + std::streamoff start; + std::streamoff 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.tellp(); + break; + default: + return STG_E_INVALIDFUNCTION; + } + new_read_position = start + liDistanceToMove.QuadPart; + if (new_read_position > m_InterStream.tellp()) + return STG_E_SEEKERROR; + + m_ReadPos = new_read_position; + if (lpNewFilePointer) + lpNewFilePointer->QuadPart = m_ReadPos; + + return S_OK; + } + HRESULT STDMETHODCALLTYPE Stat(STATSTG* pStatstg, + DWORD grfStatFlag) override { + if (!pStatstg) + return STG_E_INVALIDFUNCTION; + + ZeroMemory(pStatstg, sizeof(STATSTG)); + pStatstg->cbSize.QuadPart = m_InterStream.tellp(); + return S_OK; + } + + private: + LONG m_RefCount; + std::streamoff m_ReadPos; + std::ostringstream m_InterStream; +}; + +struct PREVIEW3_DIBITMAP { + BITMAPINFO* pbmi; + int Stride; + LPBYTE pScan0; + GpBitmap* pBitmap; + Gdiplus::BitmapData* pBitmapData; + GpStream* pStream; +}; + +PREVIEW3_DIBITMAP* LoadDIBitmap(WINDIB_Open_Args_ args) { + GpBitmap* pBitmap; + GpStream* pStream = nullptr; + CGdiplusExt& GdiplusExt = + ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt; + Gdiplus::Status status = Gdiplus::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 nullptr; + + pStream = new GpStream; + pStream->Write(args.memory_base, (ULONG)args.memory_size, nullptr); + status = CallFunc(GdipCreateBitmapFromStreamICM)(pStream, &pBitmap); + } + if (status != Gdiplus::Ok) { + if (pStream) + pStream->Release(); + + return nullptr; + } + UINT height, width; + CallFunc(GdipGetImageHeight)(pBitmap, &height); + CallFunc(GdipGetImageWidth)(pBitmap, &width); + Gdiplus::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; + Gdiplus::Rect rect(0, 0, width, height); + Gdiplus::BitmapData* pBitmapData = FX_Alloc(Gdiplus::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, (Gdiplus::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; +} + +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); +} + +} // namespace + +void* CGdiplusExt::GdiAddFontMemResourceEx(void* pFontdata, + uint32_t size, + void* pdv, + uint32_t* num_face) { + if (!m_pGdiAddFontMemResourceEx) + return nullptr; + + return m_pGdiAddFontMemResourceEx((PVOID)pFontdata, (DWORD)size, (PVOID)pdv, + (DWORD*)num_face); +} + +bool CGdiplusExt::GdiRemoveFontMemResourceEx(void* handle) { + return m_pGdiRemoveFontMemResourseEx && + m_pGdiRemoveFontMemResourseEx((HANDLE)handle); +} + +CGdiplusExt::CGdiplusExt() {} + +CGdiplusExt::~CGdiplusExt() { + FreeLibrary(m_GdiModule); + FreeLibrary(m_hModule); +} + +void CGdiplusExt::Load() { + char buf[MAX_PATH]; + GetSystemDirectoryA(buf, MAX_PATH); + ByteString dllpath = buf; + dllpath += "\\GDIPLUS.DLL"; + m_hModule = LoadLibraryA(dllpath.c_str()); + if (!m_hModule) + return; + + m_Functions.resize(FX_ArraySize(g_GdipFuncNames)); + for (size_t i = 0; i < FX_ArraySize(g_GdipFuncNames); ++i) { + m_Functions[i] = GetProcAddress(m_hModule, g_GdipFuncNames[i]); + if (!m_Functions[i]) { + m_hModule = nullptr; + return; + } + } + + uintptr_t gdiplusToken; + GdiplusStartupInput gdiplusStartupInput; + ((FuncType_GdiplusStartup)m_Functions[FuncId_GdiplusStartup])( + &gdiplusToken, &gdiplusStartupInput, nullptr); + m_GdiModule = LoadLibraryA("GDI32.DLL"); + if (!m_GdiModule) + return; + + m_pGdiAddFontMemResourceEx = + reinterpret_cast( + GetProcAddress(m_GdiModule, "AddFontMemResourceEx")); + m_pGdiRemoveFontMemResourseEx = + reinterpret_cast( + GetProcAddress(m_GdiModule, "RemoveFontMemResourceEx")); +} + +LPVOID CGdiplusExt::LoadMemFont(LPBYTE pData, uint32_t size) { + GpFontCollection* pCollection = nullptr; + CGdiplusExt& GdiplusExt = + ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt; + CallFunc(GdipNewPrivateFontCollection)(&pCollection); + GpStatus status = + CallFunc(GdipPrivateAddMemoryFont)(pCollection, pData, size); + if (status == Gdiplus::Ok) + return pCollection; + + CallFunc(GdipDeletePrivateFontCollection)(&pCollection); + return nullptr; +} +void CGdiplusExt::DeleteMemFont(LPVOID pCollection) { + CGdiplusExt& GdiplusExt = + ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt; + CallFunc(GdipDeletePrivateFontCollection)((GpFontCollection**)&pCollection); +} +bool CGdiplusExt::GdipCreateBitmap(const RetainPtr& pBitmap, + void** bitmap) { + CGdiplusExt& GdiplusExt = + ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt; + Gdiplus::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); + return status == Gdiplus::Ok; +} +bool CGdiplusExt::GdipCreateFromImage(void* bitmap, void** graphics) { + CGdiplusExt& GdiplusExt = + ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt; + GpStatus status = CallFunc(GdipGetImageGraphicsContext)( + (GpBitmap*)bitmap, (GpGraphics**)graphics); + return status == Gdiplus::Ok; +} +bool CGdiplusExt::GdipCreateFontFamilyFromName(const wchar_t* name, + void* pFontCollection, + void** pFamily) { CGdiplusExt& GdiplusExt = ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt; GpStatus status = CallFunc(GdipCreateFontFamilyFromName)( @@ -1009,141 +1375,14 @@ bool CGdiplusExt::StretchDIBits(HDC hDC, } 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, - bool bTextMode = false) { - CGdiplusExt& GdiplusExt = - ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt; - float width = pGraphState ? pGraphState->m_LineWidth : 1.0f; - if (!bTextMode) { - float unit = pMatrix - ? 1.0f / ((pMatrix->GetXUnit() + pMatrix->GetYUnit()) / 2) - : 1.0f; - if (width < unit) - width = unit; - } - GpPen* pPen = nullptr; - CallFunc(GdipCreatePen1)((Gdiplus::ARGB)argb, width, UnitWorld, &pPen); - LineCap lineCap = LineCapFlat; - DashCap dashCap = DashCapFlat; - 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 = LineJoinMiterClipped; - 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) { - float* pDashArray = FX_Alloc( - float, pGraphState->m_DashCount + pGraphState->m_DashCount % 2); - int nCount = 0; - float on_leftover = 0, off_leftover = 0; - for (int i = 0; i < pGraphState->m_DashCount; i += 2) { - float on_phase = pGraphState->m_DashArray[i]; - 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); - 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 = nullptr; - } - CallFunc(GdipSetPenMiterLimit)(pPen, pGraphState->m_MiterLimit); - return pPen; + 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 bool IsSmallTriangle(Gdiplus::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]; - - CFX_PointF p1(points[pair1].X, points[pair1].Y); - CFX_PointF p2(points[pair2].X, points[pair2].Y); - if (pMatrix) { - p1 = pMatrix->Transform(p1); - p2 = pMatrix->Transform(p2); - } - CFX_PointF diff = p1 - p2; - float distance_square = (diff.x * diff.x) + (diff.y * diff.y); - if (distance_square < (1.0f * 2 + 1.0f / 4)) { - v1 = i; - v2 = pair1; - return true; - } - } - return false; -} bool CGdiplusExt::DrawPath(HDC hDC, const CFX_PathData* pPathData, const CFX_Matrix* pObject2Device, @@ -1262,14 +1501,14 @@ bool CGdiplusExt::DrawPath(HDC hDC, return false; } if (new_fill_mode) { - GpBrush* pBrush = _GdipCreateBrush(fill_argb); + GpBrush* pBrush = GdipCreateBrushImpl(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)); + GpPen* pPen = GdipCreatePenImpl(pGraphState, pObject2Device, stroke_argb, + !!(fill_mode & FX_STROKE_TEXT_MODE)); if (nSubPathes == 1) { CallFunc(GdipDrawPath)(pGraphics, pPen, pGpPath); } else { @@ -1297,241 +1536,6 @@ bool CGdiplusExt::DrawPath(HDC hDC, return true; } -class GpStream final : public IStream { - public: - GpStream() : m_RefCount(1), m_ReadPos(0) {} - - // IUnknown - HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, - void** ppvObject) override { - if (iid == __uuidof(IUnknown) || iid == __uuidof(IStream) || - iid == __uuidof(ISequentialStream)) { - *ppvObject = static_cast(this); - AddRef(); - return S_OK; - } - return E_NOINTERFACE; - } - ULONG STDMETHODCALLTYPE AddRef() override { - return (ULONG)InterlockedIncrement(&m_RefCount); - } - ULONG STDMETHODCALLTYPE Release() override { - ULONG res = (ULONG)InterlockedDecrement(&m_RefCount); - if (res == 0) { - delete this; - } - return res; - } - - // ISequentialStream - HRESULT STDMETHODCALLTYPE Read(void* output, - ULONG cb, - ULONG* pcbRead) override { - if (pcbRead) - *pcbRead = 0; - - if (m_ReadPos >= m_InterStream.tellp()) - return HRESULT_FROM_WIN32(ERROR_END_OF_MEDIA); - - size_t bytes_left = m_InterStream.tellp() - m_ReadPos; - size_t bytes_out = - std::min(pdfium::base::checked_cast(cb), bytes_left); - memcpy(output, m_InterStream.str().c_str() + m_ReadPos, bytes_out); - m_ReadPos += bytes_out; - if (pcbRead) - *pcbRead = (ULONG)bytes_out; - - return S_OK; - } - HRESULT STDMETHODCALLTYPE Write(const void* input, - ULONG cb, - ULONG* pcbWritten) override { - if (cb <= 0) { - if (pcbWritten) - *pcbWritten = 0; - return S_OK; - } - m_InterStream.write(reinterpret_cast(input), cb); - if (pcbWritten) - *pcbWritten = cb; - return S_OK; - } - - // IStream - HRESULT STDMETHODCALLTYPE SetSize(ULARGE_INTEGER) override { - return E_NOTIMPL; - } - HRESULT STDMETHODCALLTYPE CopyTo(IStream*, - ULARGE_INTEGER, - ULARGE_INTEGER*, - ULARGE_INTEGER*) override { - return E_NOTIMPL; - } - HRESULT STDMETHODCALLTYPE Commit(DWORD) override { return E_NOTIMPL; } - HRESULT STDMETHODCALLTYPE Revert() override { return E_NOTIMPL; } - HRESULT STDMETHODCALLTYPE LockRegion(ULARGE_INTEGER, - ULARGE_INTEGER, - DWORD) override { - return E_NOTIMPL; - } - HRESULT STDMETHODCALLTYPE UnlockRegion(ULARGE_INTEGER, - ULARGE_INTEGER, - DWORD) override { - return E_NOTIMPL; - } - HRESULT STDMETHODCALLTYPE Clone(IStream** stream) override { - return E_NOTIMPL; - } - HRESULT STDMETHODCALLTYPE Seek(LARGE_INTEGER liDistanceToMove, - DWORD dwOrigin, - ULARGE_INTEGER* lpNewFilePointer) override { - std::streamoff start; - std::streamoff 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.tellp(); - break; - default: - return STG_E_INVALIDFUNCTION; - } - new_read_position = start + liDistanceToMove.QuadPart; - if (new_read_position > m_InterStream.tellp()) - return STG_E_SEEKERROR; - - m_ReadPos = new_read_position; - if (lpNewFilePointer) - lpNewFilePointer->QuadPart = m_ReadPos; - - return S_OK; - } - HRESULT STDMETHODCALLTYPE Stat(STATSTG* pStatstg, - DWORD grfStatFlag) override { - if (!pStatstg) - return STG_E_INVALIDFUNCTION; - - ZeroMemory(pStatstg, sizeof(STATSTG)); - pStatstg->cbSize.QuadPart = m_InterStream.tellp(); - return S_OK; - } - - private: - LONG m_RefCount; - std::streamoff m_ReadPos; - std::ostringstream m_InterStream; -}; - -typedef struct { - BITMAPINFO* pbmi; - int Stride; - LPBYTE pScan0; - GpBitmap* pBitmap; - Gdiplus::BitmapData* pBitmapData; - GpStream* pStream; -} PREVIEW3_DIBITMAP; - -static PREVIEW3_DIBITMAP* LoadDIBitmap(WINDIB_Open_Args_ args) { - GpBitmap* pBitmap; - GpStream* pStream = nullptr; - CGdiplusExt& GdiplusExt = - ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt; - Gdiplus::Status status = Gdiplus::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 nullptr; - - pStream = new GpStream; - pStream->Write(args.memory_base, (ULONG)args.memory_size, nullptr); - status = CallFunc(GdipCreateBitmapFromStreamICM)(pStream, &pBitmap); - } - if (status != Gdiplus::Ok) { - if (pStream) - pStream->Release(); - - return nullptr; - } - UINT height, width; - CallFunc(GdipGetImageHeight)(pBitmap, &height); - CallFunc(GdipGetImageWidth)(pBitmap, &width); - Gdiplus::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; - Gdiplus::Rect rect(0, 0, width, height); - Gdiplus::BitmapData* pBitmapData = FX_Alloc(Gdiplus::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, (Gdiplus::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); -} - -// TODO(tsepez): Really? Really? Move to header. -RetainPtr _FX_WindowsDIB_LoadFromBuf(BITMAPINFO* pbmi, - LPVOID pData, - bool bAlpha); - RetainPtr CGdiplusExt::LoadDIBitmap(WINDIB_Open_Args_ args) { PREVIEW3_DIBITMAP* pInfo = ::LoadDIBitmap(args); if (!pInfo) @@ -1549,7 +1553,7 @@ RetainPtr CGdiplusExt::LoadDIBitmap(WINDIB_Open_Args_ args) { dest_pitch); } } - RetainPtr pDIBitmap = _FX_WindowsDIB_LoadFromBuf( + RetainPtr pDIBitmap = FX_WindowsDIB_LoadFromBuf( pInfo->pbmi, pData, pInfo->pbmi->bmiHeader.biBitCount == 32); FX_Free(pData); FreeDIBitmap(pInfo); diff --git a/core/fxge/win32/win32_int.h b/core/fxge/win32/win32_int.h index 8bc8290845..f27a420734 100644 --- a/core/fxge/win32/win32_int.h +++ b/core/fxge/win32/win32_int.h @@ -29,6 +29,9 @@ typedef HANDLE(__stdcall* FuncType_GdiAddFontMemResourceEx)(PVOID pbFont, DWORD* pcFonts); typedef BOOL(__stdcall* FuncType_GdiRemoveFontMemResourceEx)(HANDLE handle); +RetainPtr FX_WindowsDIB_LoadFromBuf(BITMAPINFO* pbmi, + LPVOID pData, + bool bAlpha); class CGdiplusExt { public: CGdiplusExt(); -- cgit v1.2.3