// 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 "../../../include/fxge/fx_ge.h" | |
#if _FX_OS_ == _FX_WIN32_DESKTOP_ || _FX_OS_ == _FX_WIN64_ | |
#include <windows.h> | |
#include "../../../include/fxge/fx_ge_win32.h" | |
#include "win32_int.h" | |
#include "../Microsoft SDK/include/GdiPlus.h" | |
using namespace Gdiplus; | |
using namespace Gdiplus::DllExports; | |
#define GdiFillType2Gdip(fill_type) (fill_type == ALTERNATE ? FillModeAlternate : FillModeWinding) | |
static CombineMode GdiCombineMode2Gdip(int mode) | |
{ | |
switch (mode) { | |
case RGN_AND: | |
return CombineModeIntersect; | |
} | |
return CombineModeIntersect; | |
} | |
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 FX_UINTPTR *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 *string, 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 = FX_NEW CFX_DIBitmap; | |
if (!pStretched) { | |
return NULL; | |
} | |
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 src_count = src_width * src_height; | |
int dest_count = dest_width * dest_height; | |
int ratio = 255 * dest_count / src_count; | |
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(); | |
FX_LPBYTE 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(); | |
FX_LPBYTE 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 == NULL) { | |
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] == NULL) { | |
m_hModule = NULL; | |
return; | |
} | |
} | |
FX_UINTPTR gdiplusToken; | |
GdiplusStartupInput gdiplusStartupInput; | |
((FuncType_GdiplusStartup)m_Functions[FuncId_GdiplusStartup])(&gdiplusToken, &gdiplusStartupInput, NULL); | |
m_GdiModule = LoadLibraryA("GDI32.DLL"); | |
if (m_GdiModule == NULL) { | |
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(FX_LPCWSTR 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_AffineMatrix* 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 == NULL ? 1.0f : FXSYS_Div(1.0f, (pMatrix->GetXUnit() + pMatrix->GetYUnit()) / 2); | |
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); | |
if (!pDashArray) { | |
return NULL; | |
} | |
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 BOOL IsSmallTriangle(PointF* points, const CFX_AffineMatrix* 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 = FXSYS_Mul(dx, dx) + FXSYS_Mul(dy, dy); | |
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_AffineMatrix* 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); | |
if (!points) { | |
return FALSE; | |
} | |
BYTE * types = FX_Alloc(BYTE, nPoints); | |
if (!types) { | |
FX_Free(points); | |
return FALSE; | |
} | |
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 == NULL) { | |
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 : public IStream, public CFX_Object | |
{ | |
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; | |
} else { | |
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 != NULL) { | |
*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 = FX_MIN(cb, bytes_left); | |
FXSYS_memcpy32(Output, m_InterStream.GetBuffer() + m_ReadPos, bytes_out); | |
m_ReadPos += (FX_INT32)bytes_out; | |
if (pcbRead != NULL) { | |
*pcbRead = (ULONG)bytes_out; | |
} | |
return S_OK; | |
} | |
virtual HRESULT STDMETHODCALLTYPE Write(void const* Input, ULONG cb, ULONG* pcbWritten) | |
{ | |
if (cb <= 0) { | |
if (pcbWritten != NULL) { | |
*pcbWritten = 0; | |
} | |
return S_OK; | |
} | |
m_InterStream.InsertBlock(m_InterStream.GetLength(), Input, cb); | |
if (pcbWritten != NULL) { | |
*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 **) | |
{ | |
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 != NULL) { | |
lpNewFilePointer->QuadPart = m_ReadPos; | |
} | |
return S_OK; | |
} | |
virtual HRESULT STDMETHODCALLTYPE Stat(STATSTG* pStatstg, DWORD grfStatFlag) | |
{ | |
if (pStatstg == NULL) { | |
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 = FX_NEW GpStream; | |
if (!pStream) { | |
return NULL; | |
} | |
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); | |
if (!buf) { | |
if (pStream) { | |
pStream->Release(); | |
} | |
return NULL; | |
} | |
BITMAPINFOHEADER* pbmih = (BITMAPINFOHEADER*)buf; | |
FXSYS_memset32(buf, 0, info_size); | |
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); | |
if (!pBitmapData) { | |
if (pStream) { | |
pStream->Release(); | |
} | |
return NULL; | |
} | |
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); | |
if (!pInfo) { | |
if (pStream) { | |
pStream->Release(); | |
} | |
return NULL; | |
} | |
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 == NULL) { | |
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_Alloc(BYTE, dest_pitch * height); | |
if (pData == NULL) { | |
FreeDIBitmap(pInfo); | |
return NULL; | |
} | |
if (dest_pitch == pInfo->Stride) { | |
FXSYS_memcpy32(pData, pInfo->pScan0, dest_pitch * height); | |
} else for (int i = 0; i < height; i ++) { | |
FXSYS_memcpy32(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 |