// 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 #include namespace Gdiplus { using std::min; using std::max; } // namespace Gdiplus #include #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 = LineCapFlat; 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 = 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) { 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(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(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