1 // Copyright 2014 PDFium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com 6 7 #include "../../../include/fxge/fx_ge.h" 8 #if _FX_OS_ == _FX_WIN32_DESKTOP_ || _FX_OS_ == _FX_WIN64_ 9 #include <windows.h> 10 #include "../../../include/fxge/fx_ge_win32.h" 11 #include "win32_int.h" 12 #include "../Microsoft SDK/include/GdiPlus.h" 13 using namespace Gdiplus; 14 using namespace Gdiplus::DllExports; 15 #define GdiFillType2Gdip(fill_type) (fill_type == ALTERNATE ? FillModeAlternate : FillModeWinding) 16 static CombineMode GdiCombineMode2Gdip(int mode) 17 { 18 switch (mode) { 19 case RGN_AND: 20 return CombineModeIntersect; 21 } 22 return CombineModeIntersect; 23 } 24 enum { 25 FuncId_GdipCreatePath2, 26 FuncId_GdipSetPenDashStyle, 27 FuncId_GdipSetPenDashArray, 28 FuncId_GdipSetPenDashCap197819, 29 FuncId_GdipSetPenLineJoin, 30 FuncId_GdipSetPenWidth, 31 FuncId_GdipCreateFromHDC, 32 FuncId_GdipSetPageUnit, 33 FuncId_GdipSetSmoothingMode, 34 FuncId_GdipCreateSolidFill, 35 FuncId_GdipFillPath, 36 FuncId_GdipDeleteBrush, 37 FuncId_GdipCreatePen1, 38 FuncId_GdipSetPenMiterLimit, 39 FuncId_GdipDrawPath, 40 FuncId_GdipDeletePen, 41 FuncId_GdipDeletePath, 42 FuncId_GdipDeleteGraphics, 43 FuncId_GdipCreateBitmapFromFileICM, 44 FuncId_GdipCreateBitmapFromStreamICM, 45 FuncId_GdipGetImageHeight, 46 FuncId_GdipGetImageWidth, 47 FuncId_GdipGetImagePixelFormat, 48 FuncId_GdipBitmapLockBits, 49 FuncId_GdipGetImagePaletteSize, 50 FuncId_GdipGetImagePalette, 51 FuncId_GdipBitmapUnlockBits, 52 FuncId_GdipDisposeImage, 53 FuncId_GdipFillRectangle, 54 FuncId_GdipCreateBitmapFromScan0, 55 FuncId_GdipSetImagePalette, 56 FuncId_GdipSetInterpolationMode, 57 FuncId_GdipDrawImagePointsI, 58 FuncId_GdipCreateBitmapFromGdiDib, 59 FuncId_GdiplusStartup, 60 FuncId_GdipDrawLineI, 61 FuncId_GdipResetClip, 62 FuncId_GdipCreatePath, 63 FuncId_GdipAddPathPath, 64 FuncId_GdipSetPathFillMode, 65 FuncId_GdipSetClipPath, 66 FuncId_GdipGetClip, 67 FuncId_GdipCreateRegion, 68 FuncId_GdipGetClipBoundsI, 69 FuncId_GdipSetClipRegion, 70 FuncId_GdipWidenPath, 71 FuncId_GdipAddPathLine, 72 FuncId_GdipAddPathRectangle, 73 FuncId_GdipDeleteRegion, 74 FuncId_GdipGetDC, 75 FuncId_GdipReleaseDC, 76 FuncId_GdipSetPenLineCap197819, 77 FuncId_GdipSetPenDashOffset, 78 FuncId_GdipResetPath, 79 FuncId_GdipCreateRegionPath, 80 FuncId_GdipCreateFont, 81 FuncId_GdipGetFontSize, 82 FuncId_GdipCreateFontFamilyFromName, 83 FuncId_GdipSetTextRenderingHint, 84 FuncId_GdipDrawDriverString, 85 FuncId_GdipCreateMatrix2, 86 FuncId_GdipDeleteMatrix, 87 FuncId_GdipSetWorldTransform, 88 FuncId_GdipResetWorldTransform, 89 FuncId_GdipDeleteFontFamily, 90 FuncId_GdipDeleteFont, 91 FuncId_GdipNewPrivateFontCollection, 92 FuncId_GdipDeletePrivateFontCollection, 93 FuncId_GdipPrivateAddMemoryFont, 94 FuncId_GdipGetFontCollectionFamilyList, 95 FuncId_GdipGetFontCollectionFamilyCount, 96 FuncId_GdipSetTextContrast, 97 FuncId_GdipSetPixelOffsetMode, 98 FuncId_GdipGetImageGraphicsContext, 99 FuncId_GdipDrawImageI, 100 FuncId_GdipDrawImageRectI, 101 FuncId_GdipDrawString, 102 FuncId_GdipSetPenTransform, 103 }; 104 static LPCSTR g_GdipFuncNames[] = { 105 "GdipCreatePath2", 106 "GdipSetPenDashStyle", 107 "GdipSetPenDashArray", 108 "GdipSetPenDashCap197819", 109 "GdipSetPenLineJoin", 110 "GdipSetPenWidth", 111 "GdipCreateFromHDC", 112 "GdipSetPageUnit", 113 "GdipSetSmoothingMode", 114 "GdipCreateSolidFill", 115 "GdipFillPath", 116 "GdipDeleteBrush", 117 "GdipCreatePen1", 118 "GdipSetPenMiterLimit", 119 "GdipDrawPath", 120 "GdipDeletePen", 121 "GdipDeletePath", 122 "GdipDeleteGraphics", 123 "GdipCreateBitmapFromFileICM", 124 "GdipCreateBitmapFromStreamICM", 125 "GdipGetImageHeight", 126 "GdipGetImageWidth", 127 "GdipGetImagePixelFormat", 128 "GdipBitmapLockBits", 129 "GdipGetImagePaletteSize", 130 "GdipGetImagePalette", 131 "GdipBitmapUnlockBits", 132 "GdipDisposeImage", 133 "GdipFillRectangle", 134 "GdipCreateBitmapFromScan0", 135 "GdipSetImagePalette", 136 "GdipSetInterpolationMode", 137 "GdipDrawImagePointsI", 138 "GdipCreateBitmapFromGdiDib", 139 "GdiplusStartup", 140 "GdipDrawLineI", 141 "GdipResetClip", 142 "GdipCreatePath", 143 "GdipAddPathPath", 144 "GdipSetPathFillMode", 145 "GdipSetClipPath", 146 "GdipGetClip", 147 "GdipCreateRegion", 148 "GdipGetClipBoundsI", 149 "GdipSetClipRegion", 150 "GdipWidenPath", 151 "GdipAddPathLine", 152 "GdipAddPathRectangle", 153 "GdipDeleteRegion", 154 "GdipGetDC", 155 "GdipReleaseDC", 156 "GdipSetPenLineCap197819", 157 "GdipSetPenDashOffset", 158 "GdipResetPath", 159 "GdipCreateRegionPath", 160 "GdipCreateFont", 161 "GdipGetFontSize", 162 "GdipCreateFontFamilyFromName", 163 "GdipSetTextRenderingHint", 164 "GdipDrawDriverString", 165 "GdipCreateMatrix2", 166 "GdipDeleteMatrix", 167 "GdipSetWorldTransform", 168 "GdipResetWorldTransform", 169 "GdipDeleteFontFamily", 170 "GdipDeleteFont", 171 "GdipNewPrivateFontCollection", 172 "GdipDeletePrivateFontCollection", 173 "GdipPrivateAddMemoryFont", 174 "GdipGetFontCollectionFamilyList", 175 "GdipGetFontCollectionFamilyCount", 176 "GdipSetTextContrast", 177 "GdipSetPixelOffsetMode", 178 "GdipGetImageGraphicsContext", 179 "GdipDrawImageI", 180 "GdipDrawImageRectI", 181 "GdipDrawString", 182 "GdipSetPenTransform", 183 }; 184 typedef GpStatus (WINGDIPAPI *FuncType_GdipCreatePath2)(GDIPCONST GpPointF*, GDIPCONST BYTE*, INT, GpFillMode, GpPath **path); 185 typedef GpStatus (WINGDIPAPI *FuncType_GdipSetPenDashStyle)(GpPen *pen, GpDashStyle dashstyle); 186 typedef GpStatus (WINGDIPAPI *FuncType_GdipSetPenDashArray)(GpPen *pen, GDIPCONST REAL *dash, INT count); 187 typedef GpStatus (WINGDIPAPI *FuncType_GdipSetPenDashCap197819)(GpPen *pen, GpDashCap dashCap); 188 typedef GpStatus (WINGDIPAPI *FuncType_GdipSetPenLineJoin)(GpPen *pen, GpLineJoin lineJoin); 189 typedef GpStatus (WINGDIPAPI *FuncType_GdipSetPenWidth)(GpPen *pen, REAL width); 190 typedef GpStatus (WINGDIPAPI *FuncType_GdipCreateFromHDC)(HDC hdc, GpGraphics **graphics); 191 typedef GpStatus (WINGDIPAPI *FuncType_GdipSetPageUnit)(GpGraphics *graphics, GpUnit unit); 192 typedef GpStatus (WINGDIPAPI *FuncType_GdipSetSmoothingMode)(GpGraphics *graphics, SmoothingMode smoothingMode); 193 typedef GpStatus (WINGDIPAPI *FuncType_GdipCreateSolidFill)(ARGB color, GpSolidFill **brush); 194 typedef GpStatus (WINGDIPAPI *FuncType_GdipFillPath)(GpGraphics *graphics, GpBrush *brush, GpPath *path); 195 typedef GpStatus (WINGDIPAPI *FuncType_GdipDeleteBrush)(GpBrush *brush); 196 typedef GpStatus (WINGDIPAPI *FuncType_GdipCreatePen1)(ARGB color, REAL width, GpUnit unit, GpPen **pen); 197 typedef GpStatus (WINGDIPAPI *FuncType_GdipSetPenMiterLimit)(GpPen *pen, REAL miterLimit); 198 typedef GpStatus (WINGDIPAPI *FuncType_GdipDrawPath)(GpGraphics *graphics, GpPen *pen, GpPath *path); 199 typedef GpStatus (WINGDIPAPI *FuncType_GdipDeletePen)(GpPen *pen); 200 typedef GpStatus (WINGDIPAPI *FuncType_GdipDeletePath)(GpPath* path); 201 typedef GpStatus (WINGDIPAPI *FuncType_GdipDeleteGraphics)(GpGraphics *graphics); 202 typedef GpStatus (WINGDIPAPI *FuncType_GdipCreateBitmapFromFileICM)(GDIPCONST WCHAR* filename, GpBitmap **bitmap); 203 typedef GpStatus (WINGDIPAPI *FuncType_GdipCreateBitmapFromStreamICM)(IStream* stream, GpBitmap **bitmap); 204 typedef GpStatus (WINGDIPAPI *FuncType_GdipGetImageWidth)(GpImage *image, UINT *width); 205 typedef GpStatus (WINGDIPAPI *FuncType_GdipGetImageHeight)(GpImage *image, UINT *height); 206 typedef GpStatus (WINGDIPAPI *FuncType_GdipGetImagePixelFormat)(GpImage *image, PixelFormat *format); 207 typedef GpStatus (WINGDIPAPI *FuncType_GdipBitmapLockBits)(GpBitmap* bitmap, GDIPCONST GpRect* rect, UINT flags, PixelFormat format, BitmapData* lockedBitmapData); 208 typedef GpStatus (WINGDIPAPI *FuncType_GdipGetImagePalette)(GpImage *image, ColorPalette *palette, INT size); 209 typedef GpStatus (WINGDIPAPI *FuncType_GdipGetImagePaletteSize)(GpImage *image, INT *size); 210 typedef GpStatus (WINGDIPAPI *FuncType_GdipBitmapUnlockBits)(GpBitmap* bitmap, BitmapData* lockedBitmapData); 211 typedef GpStatus (WINGDIPAPI *FuncType_GdipDisposeImage)(GpImage *image); 212 typedef GpStatus (WINGDIPAPI *FuncType_GdipFillRectangle)(GpGraphics *graphics, GpBrush *brush, REAL x, REAL y, REAL width, REAL height); 213 typedef GpStatus (WINGDIPAPI *FuncType_GdipCreateBitmapFromScan0)(INT width, INT height, INT stride, PixelFormat format, BYTE* scan0, GpBitmap** bitmap); 214 typedef GpStatus (WINGDIPAPI *FuncType_GdipSetImagePalette)(GpImage *image, GDIPCONST ColorPalette *palette); 215 typedef GpStatus (WINGDIPAPI *FuncType_GdipSetInterpolationMode)(GpGraphics *graphics, InterpolationMode interpolationMode); 216 typedef GpStatus (WINGDIPAPI *FuncType_GdipDrawImagePointsI)(GpGraphics *graphics, GpImage *image, GDIPCONST GpPoint *dstpoints, INT count); 217 typedef GpStatus (WINGDIPAPI *FuncType_GdipCreateBitmapFromGdiDib)(GDIPCONST BITMAPINFO* gdiBitmapInfo, VOID* gdiBitmapData, GpBitmap** bitmap); 218 typedef Status (WINAPI *FuncType_GdiplusStartup)(OUT FX_UINTPTR *token, const GdiplusStartupInput *input, OUT GdiplusStartupOutput *output); 219 typedef GpStatus (WINGDIPAPI *FuncType_GdipDrawLineI)(GpGraphics *graphics, GpPen *pen, int x1, int y1, int x2, int y2); 220 typedef GpStatus (WINGDIPAPI *FuncType_GdipResetClip)(GpGraphics *graphics); 221 typedef GpStatus (WINGDIPAPI *FuncType_GdipCreatePath)(GpFillMode brushMode, GpPath **path); 222 typedef GpStatus (WINGDIPAPI *FuncType_GdipAddPathPath)(GpPath *path, GDIPCONST GpPath* addingPath, BOOL connect); 223 typedef GpStatus (WINGDIPAPI *FuncType_GdipSetPathFillMode)(GpPath *path, GpFillMode fillmode); 224 typedef GpStatus (WINGDIPAPI *FuncType_GdipSetClipPath)(GpGraphics *graphics, GpPath *path, CombineMode combineMode); 225 typedef GpStatus (WINGDIPAPI *FuncType_GdipGetClip)(GpGraphics *graphics, GpRegion *region); 226 typedef GpStatus (WINGDIPAPI *FuncType_GdipCreateRegion)(GpRegion **region); 227 typedef GpStatus (WINGDIPAPI *FuncType_GdipGetClipBoundsI)(GpGraphics *graphics, GpRect *rect); 228 typedef GpStatus (WINGDIPAPI *FuncType_GdipSetClipRegion)(GpGraphics *graphics, GpRegion *region, CombineMode combineMode); 229 typedef GpStatus (WINGDIPAPI *FuncType_GdipWidenPath)(GpPath *nativePath, GpPen *pen, GpMatrix *matrix, REAL flatness); 230 typedef GpStatus (WINGDIPAPI *FuncType_GdipAddPathLine)(GpPath *path, REAL x1, REAL y1, REAL x2, REAL y2); 231 typedef GpStatus (WINGDIPAPI *FuncType_GdipAddPathRectangle)(GpPath *path, REAL x, REAL y, REAL width, REAL height); 232 typedef GpStatus (WINGDIPAPI *FuncType_GdipDeleteRegion)(GpRegion *region); 233 typedef GpStatus (WINGDIPAPI *FuncType_GdipGetDC)(GpGraphics* graphics, HDC * hdc); 234 typedef GpStatus (WINGDIPAPI *FuncType_GdipReleaseDC)(GpGraphics* graphics, HDC hdc); 235 typedef GpStatus (WINGDIPAPI *FuncType_GdipSetPenLineCap197819)(GpPen *pen, GpLineCap startCap, GpLineCap endCap, GpDashCap dashCap); 236 typedef GpStatus (WINGDIPAPI *FuncType_GdipSetPenDashOffset)(GpPen *pen, REAL offset); 237 typedef GpStatus (WINGDIPAPI *FuncType_GdipResetPath)(GpPath *path); 238 typedef GpStatus (WINGDIPAPI *FuncType_GdipCreateRegionPath)(GpPath *path, GpRegion **region); 239 typedef GpStatus (WINGDIPAPI *FuncType_GdipCreateFont)(GDIPCONST GpFontFamily *fontFamily, REAL emSize, INT style, Unit unit, GpFont **font); 240 typedef GpStatus (WINGDIPAPI *FuncType_GdipGetFontSize)(GpFont *font, REAL *size); 241 typedef GpStatus (WINGDIPAPI *FuncType_GdipCreateFontFamilyFromName)(GDIPCONST WCHAR *name, GpFontCollection *fontCollection, GpFontFamily **FontFamily); 242 typedef GpStatus (WINGDIPAPI *FuncType_GdipSetTextRenderingHint)(GpGraphics *graphics, TextRenderingHint mode); 243 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); 244 typedef GpStatus (WINGDIPAPI *FuncType_GdipCreateMatrix2)(REAL m11, REAL m12, REAL m21, REAL m22, REAL dx, REAL dy, GpMatrix **matrix); 245 typedef GpStatus (WINGDIPAPI *FuncType_GdipDeleteMatrix)(GpMatrix *matrix); 246 typedef GpStatus (WINGDIPAPI *FuncType_GdipSetWorldTransform)(GpGraphics *graphics, GpMatrix *matrix); 247 typedef GpStatus (WINGDIPAPI *FuncType_GdipResetWorldTransform)(GpGraphics *graphics); 248 typedef GpStatus (WINGDIPAPI *FuncType_GdipDeleteFontFamily)(GpFontFamily *FontFamily); 249 typedef GpStatus (WINGDIPAPI *FuncType_GdipDeleteFont)(GpFont* font); 250 typedef GpStatus (WINGDIPAPI *FuncType_GdipNewPrivateFontCollection)(GpFontCollection** fontCollection); 251 typedef GpStatus (WINGDIPAPI *FuncType_GdipDeletePrivateFontCollection)(GpFontCollection** fontCollection); 252 typedef GpStatus (WINGDIPAPI *FuncType_GdipPrivateAddMemoryFont)(GpFontCollection* fontCollection, GDIPCONST void* memory, INT length); 253 typedef GpStatus (WINGDIPAPI *FuncType_GdipGetFontCollectionFamilyList)(GpFontCollection* fontCollection, INT numSought, GpFontFamily* gpfamilies[], INT* numFound); 254 typedef GpStatus (WINGDIPAPI *FuncType_GdipGetFontCollectionFamilyCount)(GpFontCollection* fontCollection, INT* numFound); 255 typedef GpStatus (WINGDIPAPI *FuncType_GdipSetTextContrast)(GpGraphics *graphics, UINT contrast); 256 typedef GpStatus (WINGDIPAPI *FuncType_GdipSetPixelOffsetMode)(GpGraphics* graphics, PixelOffsetMode pixelOffsetMode); 257 typedef GpStatus (WINGDIPAPI *FuncType_GdipGetImageGraphicsContext)(GpImage *image, GpGraphics **graphics); 258 typedef GpStatus (WINGDIPAPI *FuncType_GdipDrawImageI)(GpGraphics *graphics, GpImage *image, INT x, INT y); 259 typedef GpStatus (WINGDIPAPI *FuncType_GdipDrawImageRectI)(GpGraphics *graphics, GpImage *image, INT x, INT y, INT width, INT height); 260 typedef GpStatus (WINGDIPAPI *FuncType_GdipDrawString)(GpGraphics *graphics, GDIPCONST WCHAR *string, INT length, GDIPCONST GpFont *font, GDIPCONST RectF *layoutRect, GDIPCONST GpStringFormat *stringFormat, GDIPCONST GpBrush *brush); 261 typedef GpStatus (WINGDIPAPI *FuncType_GdipSetPenTransform)(GpPen *pen, GpMatrix *matrix); 262 #define CallFunc(funcname) ((FuncType_##funcname)GdiplusExt.m_Functions[FuncId_##funcname]) 263 typedef HANDLE (__stdcall *FuncType_GdiAddFontMemResourceEx)(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts); 264 typedef BOOL (__stdcall *FuncType_GdiRemoveFontMemResourceEx)(HANDLE handle); 265 void* CGdiplusExt::GdiAddFontMemResourceEx(void *pFontdata, FX_DWORD size, void* pdv, FX_DWORD* num_face) 266 { 267 if (m_pGdiAddFontMemResourceEx) { 268 return ((FuncType_GdiAddFontMemResourceEx)m_pGdiAddFontMemResourceEx)((PVOID)pFontdata, (DWORD)size, (PVOID)pdv, (DWORD*)num_face); 269 } 270 return NULL; 271 } 272 FX_BOOL CGdiplusExt::GdiRemoveFontMemResourceEx(void* handle) 273 { 274 if (m_pGdiRemoveFontMemResourseEx) { 275 return ((FuncType_GdiRemoveFontMemResourceEx)m_pGdiRemoveFontMemResourseEx)((HANDLE)handle); 276 } 277 return FALSE; 278 } 279 static GpBrush* _GdipCreateBrush(DWORD argb) 280 { 281 CGdiplusExt& GdiplusExt = ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt; 282 GpSolidFill* solidBrush = NULL; 283 CallFunc(GdipCreateSolidFill)((ARGB)argb, &solidBrush); 284 return solidBrush; 285 } 286 static CFX_DIBitmap* _StretchMonoToGray(int dest_width, int dest_height, 287 const CFX_DIBitmap* pSource, FX_RECT* pClipRect) 288 { 289 FX_BOOL bFlipX = dest_width < 0; 290 if (bFlipX) { 291 dest_width = -dest_width; 292 } 293 FX_BOOL bFlipY = dest_height < 0; 294 if (bFlipY) { 295 dest_height = -dest_height; 296 } 297 int result_width = pClipRect->Width(); 298 int result_height = pClipRect->Height(); 299 int result_pitch = (result_width + 3) / 4 * 4; 300 CFX_DIBitmap* pStretched = FX_NEW CFX_DIBitmap; 301 if (!pStretched) { 302 return NULL; 303 } 304 if (!pStretched->Create(result_width, result_height, FXDIB_8bppRgb)) { 305 delete pStretched; 306 return NULL; 307 } 308 LPBYTE dest_buf = pStretched->GetBuffer(); 309 int src_width = pSource->GetWidth(); 310 int src_height = pSource->GetHeight(); 311 int src_count = src_width * src_height; 312 int dest_count = dest_width * dest_height; 313 int ratio = 255 * dest_count / src_count; 314 int y_unit = src_height / dest_height; 315 int x_unit = src_width / dest_width; 316 int area_unit = y_unit * x_unit; 317 LPBYTE src_buf = pSource->GetBuffer(); 318 int src_pitch = pSource->GetPitch(); 319 for (int dest_y = 0; dest_y < result_height; dest_y ++) { 320 LPBYTE dest_scan = dest_buf + dest_y * result_pitch; 321 int src_y_start = bFlipY ? (dest_height - 1 - dest_y - pClipRect->top) : (dest_y + pClipRect->top); 322 src_y_start = src_y_start * src_height / dest_height; 323 LPBYTE src_scan = src_buf + src_y_start * src_pitch; 324 for (int dest_x = 0; dest_x < result_width; dest_x ++) { 325 int sum = 0; 326 int src_x_start = bFlipX ? (dest_width - 1 - dest_x - pClipRect->left) : (dest_x + pClipRect->left); 327 src_x_start = src_x_start * src_width / dest_width; 328 int src_x_end = src_x_start + x_unit; 329 LPBYTE src_line = src_scan; 330 for (int src_y = 0; src_y < y_unit; src_y ++) { 331 for (int src_x = src_x_start; src_x < src_x_end; src_x ++) { 332 if (!(src_line[src_x / 8] & (1 << (7 - src_x % 8)))) { 333 sum += 255; 334 } 335 } 336 src_line += src_pitch; 337 } 338 dest_scan[dest_x] = 255 - sum / area_unit; 339 } 340 } 341 return pStretched; 342 } 343 static void OutputImageMask(GpGraphics* pGraphics, BOOL bMonoDevice, const CFX_DIBitmap* pBitmap, int dest_left, int dest_top, 344 int dest_width, int dest_height, FX_ARGB argb, const FX_RECT* pClipRect) 345 { 346 ASSERT(pBitmap->GetBPP() == 1); 347 CGdiplusExt& GdiplusExt = ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt; 348 int src_width = pBitmap->GetWidth(), src_height = pBitmap->GetHeight(); 349 int src_pitch = pBitmap->GetPitch(); 350 FX_LPBYTE scan0 = pBitmap->GetBuffer(); 351 if (src_width == 1 && src_height == 1) { 352 if ((scan0[0] & 0x80) == 0) { 353 return; 354 } 355 GpSolidFill* solidBrush; 356 CallFunc(GdipCreateSolidFill)((ARGB)argb, &solidBrush); 357 if (dest_width < 0) { 358 dest_width = -dest_width; 359 dest_left -= dest_width; 360 } 361 if (dest_height < 0) { 362 dest_height = -dest_height; 363 dest_top -= dest_height; 364 } 365 CallFunc(GdipFillRectangle)(pGraphics, solidBrush, (float)dest_left, (float)dest_top, 366 (float)dest_width, (float)dest_height); 367 CallFunc(GdipDeleteBrush)(solidBrush); 368 return; 369 } 370 if (!bMonoDevice && abs(dest_width) < src_width && abs(dest_height) < src_height) { 371 FX_RECT image_rect(dest_left, dest_top, dest_left + dest_width, dest_top + dest_height); 372 image_rect.Normalize(); 373 FX_RECT image_clip = image_rect; 374 image_clip.Intersect(*pClipRect); 375 if (image_clip.IsEmpty()) { 376 return; 377 } 378 image_clip.Offset(-image_rect.left, -image_rect.top); 379 CFX_DIBitmap* pStretched = NULL; 380 if (src_width * src_height > 10000) { 381 pStretched = _StretchMonoToGray(dest_width, dest_height, pBitmap, &image_clip); 382 } else { 383 pStretched = pBitmap->StretchTo(dest_width, dest_height, FALSE, &image_clip); 384 } 385 GpBitmap* bitmap; 386 CallFunc(GdipCreateBitmapFromScan0)(image_clip.Width(), image_clip.Height(), 387 (image_clip.Width() + 3) / 4 * 4, PixelFormat8bppIndexed, pStretched->GetBuffer(), &bitmap); 388 int a, r, g, b; 389 ArgbDecode(argb, a, r, g, b); 390 UINT pal[258]; 391 pal[0] = 0; 392 pal[1] = 256; 393 for (int i = 0; i < 256; i ++) { 394 pal[i + 2] = ArgbEncode(i * a / 255, r, g, b); 395 } 396 CallFunc(GdipSetImagePalette)(bitmap, (ColorPalette*)pal); 397 CallFunc(GdipDrawImageI)(pGraphics, bitmap, image_rect.left + image_clip.left, 398 image_rect.top + image_clip.top); 399 CallFunc(GdipDisposeImage)(bitmap); 400 delete pStretched; 401 return; 402 } 403 GpBitmap* bitmap; 404 CallFunc(GdipCreateBitmapFromScan0)(src_width, src_height, src_pitch, PixelFormat1bppIndexed, scan0, &bitmap); 405 UINT palette[4] = { PaletteFlagsHasAlpha, 2, 0, argb }; 406 CallFunc(GdipSetImagePalette)(bitmap, (ColorPalette*)palette); 407 Point destinationPoints[] = { 408 Point(dest_left, dest_top), 409 Point(dest_left + dest_width, dest_top), 410 Point(dest_left, dest_top + dest_height) 411 }; 412 CallFunc(GdipDrawImagePointsI)(pGraphics, bitmap, destinationPoints, 3); 413 CallFunc(GdipDisposeImage)(bitmap); 414 } 415 static void OutputImage(GpGraphics* pGraphics, const CFX_DIBitmap* pBitmap, const FX_RECT* pSrcRect, 416 int dest_left, int dest_top, int dest_width, int dest_height) 417 { 418 int src_width = pSrcRect->Width(), src_height = pSrcRect->Height(); 419 CGdiplusExt& GdiplusExt = ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt; 420 if (pBitmap->GetBPP() == 1 && (pSrcRect->left % 8)) { 421 FX_RECT new_rect(0, 0, src_width, src_height); 422 CFX_DIBitmap* pCloned = pBitmap->Clone(pSrcRect); 423 if (!pCloned) { 424 return; 425 } 426 OutputImage(pGraphics, pCloned, &new_rect, dest_left, dest_top, dest_width, dest_height); 427 delete pCloned; 428 return; 429 } 430 int src_pitch = pBitmap->GetPitch(); 431 FX_LPBYTE scan0 = pBitmap->GetBuffer() + pSrcRect->top * src_pitch + pBitmap->GetBPP() * pSrcRect->left / 8; 432 GpBitmap* bitmap = NULL; 433 switch (pBitmap->GetFormat()) { 434 case FXDIB_Argb: 435 CallFunc(GdipCreateBitmapFromScan0)(src_width, src_height, src_pitch, 436 PixelFormat32bppARGB, scan0, &bitmap); 437 break; 438 case FXDIB_Rgb32: 439 CallFunc(GdipCreateBitmapFromScan0)(src_width, src_height, src_pitch, 440 PixelFormat32bppRGB, scan0, &bitmap); 441 break; 442 case FXDIB_Rgb: 443 CallFunc(GdipCreateBitmapFromScan0)(src_width, src_height, src_pitch, 444 PixelFormat24bppRGB, scan0, &bitmap); 445 break; 446 case FXDIB_8bppRgb: { 447 CallFunc(GdipCreateBitmapFromScan0)(src_width, src_height, src_pitch, 448 PixelFormat8bppIndexed, scan0, &bitmap); 449 UINT pal[258]; 450 pal[0] = 0; 451 pal[1] = 256; 452 for (int i = 0; i < 256; i ++) { 453 pal[i + 2] = pBitmap->GetPaletteEntry(i); 454 } 455 CallFunc(GdipSetImagePalette)(bitmap, (ColorPalette*)pal); 456 break; 457 } 458 case FXDIB_1bppRgb: { 459 CallFunc(GdipCreateBitmapFromScan0)(src_width, src_height, src_pitch, 460 PixelFormat1bppIndexed, scan0, &bitmap); 461 break; 462 } 463 } 464 if (dest_height < 0) { 465 dest_height --; 466 } 467 if (dest_width < 0) { 468 dest_width --; 469 } 470 Point destinationPoints[] = { 471 Point(dest_left, dest_top), 472 Point(dest_left + dest_width, dest_top), 473 Point(dest_left, dest_top + dest_height) 474 }; 475 CallFunc(GdipDrawImagePointsI)(pGraphics, bitmap, destinationPoints, 3); 476 CallFunc(GdipDisposeImage)(bitmap); 477 } 478 CGdiplusExt::CGdiplusExt() 479 { 480 m_hModule = NULL; 481 m_GdiModule = NULL; 482 for (int i = 0; i < sizeof g_GdipFuncNames / sizeof(LPCSTR); i ++) { 483 m_Functions[i] = NULL; 484 } 485 m_pGdiAddFontMemResourceEx = NULL; 486 m_pGdiRemoveFontMemResourseEx = NULL; 487 } 488 void CGdiplusExt::Load() 489 { 490 CFX_ByteString strPlusPath = ""; 491 FX_CHAR buf[MAX_PATH]; 492 GetSystemDirectoryA(buf, MAX_PATH); 493 strPlusPath += buf; 494 strPlusPath += "\\"; 495 strPlusPath += "GDIPLUS.DLL"; 496 m_hModule = LoadLibraryA(strPlusPath); 497 if (m_hModule == NULL) { 498 return; 499 } 500 for (int i = 0; i < sizeof g_GdipFuncNames / sizeof(LPCSTR); i ++) { 501 m_Functions[i] = GetProcAddress(m_hModule, g_GdipFuncNames[i]); 502 if (m_Functions[i] == NULL) { 503 m_hModule = NULL; 504 return; 505 } 506 } 507 FX_UINTPTR gdiplusToken; 508 GdiplusStartupInput gdiplusStartupInput; 509 ((FuncType_GdiplusStartup)m_Functions[FuncId_GdiplusStartup])(&gdiplusToken, &gdiplusStartupInput, NULL); 510 m_GdiModule = LoadLibraryA("GDI32.DLL"); 511 if (m_GdiModule == NULL) { 512 return; 513 } 514 m_pGdiAddFontMemResourceEx = GetProcAddress(m_GdiModule, "AddFontMemResourceEx"); 515 m_pGdiRemoveFontMemResourseEx = GetProcAddress(m_GdiModule, "RemoveFontMemResourceEx"); 516 } 517 CGdiplusExt::~CGdiplusExt() 518 { 519 } 520 LPVOID CGdiplusExt::LoadMemFont(LPBYTE pData, FX_DWORD size) 521 { 522 GpFontCollection* pCollection = NULL; 523 CGdiplusExt& GdiplusExt = ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt; 524 CallFunc(GdipNewPrivateFontCollection)(&pCollection); 525 GpStatus status = CallFunc(GdipPrivateAddMemoryFont)(pCollection, pData, size); 526 if (status == Ok) { 527 return pCollection; 528 } 529 CallFunc(GdipDeletePrivateFontCollection)(&pCollection); 530 return NULL; 531 } 532 void CGdiplusExt::DeleteMemFont(LPVOID pCollection) 533 { 534 CGdiplusExt& GdiplusExt = ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt; 535 CallFunc(GdipDeletePrivateFontCollection)((GpFontCollection**)&pCollection); 536 } 537 FX_BOOL CGdiplusExt::GdipCreateBitmap(CFX_DIBitmap* pBitmap, void**bitmap) 538 { 539 CGdiplusExt& GdiplusExt = ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt; 540 PixelFormat format; 541 switch (pBitmap->GetFormat()) { 542 case FXDIB_Rgb: 543 format = PixelFormat24bppRGB; 544 break; 545 case FXDIB_Rgb32: 546 format = PixelFormat32bppRGB; 547 break; 548 case FXDIB_Argb: 549 format = PixelFormat32bppARGB; 550 break; 551 default: 552 return FALSE; 553 } 554 GpStatus status = CallFunc(GdipCreateBitmapFromScan0)(pBitmap->GetWidth(), pBitmap->GetHeight(), 555 pBitmap->GetPitch(), format, pBitmap->GetBuffer(), (GpBitmap**)bitmap); 556 if (status == Ok) { 557 return TRUE; 558 } 559 return FALSE; 560 } 561 FX_BOOL CGdiplusExt::GdipCreateFromImage(void* bitmap, void** graphics) 562 { 563 CGdiplusExt& GdiplusExt = ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt; 564 GpStatus status = CallFunc(GdipGetImageGraphicsContext)((GpBitmap*)bitmap, (GpGraphics**)graphics); 565 if (status == Ok) { 566 return TRUE; 567 } 568 return FALSE; 569 } 570 FX_BOOL CGdiplusExt::GdipCreateFontFamilyFromName(FX_LPCWSTR name, void* pFontCollection, void**pFamily) 571 { 572 CGdiplusExt& GdiplusExt = ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt; 573 GpStatus status = CallFunc(GdipCreateFontFamilyFromName)((GDIPCONST WCHAR *)name, (GpFontCollection*)pFontCollection, (GpFontFamily**)pFamily); 574 if (status == Ok) { 575 return TRUE; 576 } 577 return FALSE; 578 } 579 FX_BOOL CGdiplusExt::GdipCreateFontFromFamily(void* pFamily, FX_FLOAT font_size, int fontstyle, int flag, void** pFont) 580 { 581 CGdiplusExt& GdiplusExt = ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt; 582 GpStatus status = CallFunc(GdipCreateFont)((GpFontFamily*)pFamily, font_size, fontstyle, Unit(flag), (GpFont**)pFont); 583 if (status == Ok) { 584 return TRUE; 585 } 586 return FALSE; 587 } 588 void CGdiplusExt::GdipGetFontSize(void *pFont, FX_FLOAT *size) 589 { 590 REAL get_size; 591 CGdiplusExt& GdiplusExt = ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt; 592 GpStatus status = CallFunc(GdipGetFontSize)((GpFont *)pFont, (REAL*)&get_size); 593 if (status == Ok) { 594 *size = (FX_FLOAT)get_size; 595 } else { 596 *size = 0; 597 } 598 } 599 void CGdiplusExt::GdipSetTextRenderingHint(void* graphics, int mode) 600 { 601 CGdiplusExt& GdiplusExt = ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt; 602 CallFunc(GdipSetTextRenderingHint)((GpGraphics*)graphics, (TextRenderingHint)mode); 603 } 604 void CGdiplusExt::GdipSetPageUnit(void* graphics, FX_DWORD unit) 605 { 606 CGdiplusExt& GdiplusExt = ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt; 607 CallFunc(GdipSetPageUnit)((GpGraphics*)graphics, (GpUnit)unit); 608 } 609 FX_BOOL CGdiplusExt::GdipDrawDriverString(void *graphics, unsigned short *text, int length, 610 void *font, void* brush, void *positions, int flags, const void *matrix) 611 { 612 CGdiplusExt& GdiplusExt = ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt; 613 GpStatus status = CallFunc(GdipDrawDriverString)((GpGraphics*)graphics, (GDIPCONST UINT16 *)text, (INT)length, (GDIPCONST GpFont *)font, (GDIPCONST GpBrush*)brush, 614 (GDIPCONST PointF *)positions, (INT)flags, (GDIPCONST GpMatrix *)matrix); 615 if (status == Ok) { 616 return TRUE; 617 } 618 return FALSE; 619 } 620 void CGdiplusExt::GdipCreateBrush(FX_DWORD fill_argb, void** pBrush) 621 { 622 CGdiplusExt& GdiplusExt = ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt; 623 CallFunc(GdipCreateSolidFill)((ARGB)fill_argb, (GpSolidFill**)pBrush); 624 } 625 void CGdiplusExt::GdipDeleteBrush(void* pBrush) 626 { 627 CGdiplusExt& GdiplusExt = ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt; 628 CallFunc(GdipDeleteBrush)((GpSolidFill*)pBrush); 629 } 630 void* CGdiplusExt::GdipCreateFontFromCollection(void* pFontCollection, FX_FLOAT font_size, int fontstyle) 631 { 632 CGdiplusExt& GdiplusExt = ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt; 633 int numFamilies = 0; 634 GpStatus status = CallFunc(GdipGetFontCollectionFamilyCount)((GpFontCollection*)pFontCollection, &numFamilies); 635 if (status != Ok) { 636 return NULL; 637 } 638 GpFontFamily* family_list[1]; 639 status = CallFunc(GdipGetFontCollectionFamilyList)((GpFontCollection*)pFontCollection, 1, family_list, &numFamilies); 640 if (status != Ok) { 641 return NULL; 642 } 643 GpFont* pFont = NULL; 644 status = CallFunc(GdipCreateFont)(family_list[0], font_size, fontstyle, UnitPixel, &pFont); 645 if (status != Ok) { 646 return NULL; 647 } 648 return pFont; 649 } 650 void CGdiplusExt::GdipCreateMatrix(FX_FLOAT a, FX_FLOAT b, FX_FLOAT c, FX_FLOAT d, FX_FLOAT e, FX_FLOAT f, void** matrix) 651 { 652 CGdiplusExt& GdiplusExt = ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt; 653 CallFunc(GdipCreateMatrix2)(a, b, c, d, e, f, (GpMatrix**)matrix); 654 } 655 void CGdiplusExt::GdipDeleteMatrix(void* matrix) 656 { 657 CGdiplusExt& GdiplusExt = ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt; 658 CallFunc(GdipDeleteMatrix)((GpMatrix*)matrix); 659 } 660 void CGdiplusExt::GdipDeleteFontFamily(void* pFamily) 661 { 662 CGdiplusExt& GdiplusExt = ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt; 663 CallFunc(GdipDeleteFontFamily)((GpFontFamily*)pFamily); 664 } 665 void CGdiplusExt::GdipDeleteFont(void* pFont) 666 { 667 CGdiplusExt& GdiplusExt = ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt; 668 CallFunc(GdipDeleteFont)((GpFont*)pFont); 669 } 670 void CGdiplusExt::GdipSetWorldTransform(void* graphics, void* pMatrix) 671 { 672 CGdiplusExt& GdiplusExt = ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt; 673 CallFunc(GdipSetWorldTransform)((GpGraphics*)graphics, (GpMatrix*)pMatrix); 674 } 675 void CGdiplusExt::GdipDisposeImage(void* bitmap) 676 { 677 CGdiplusExt& GdiplusExt = ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt; 678 CallFunc(GdipDisposeImage)((GpBitmap*)bitmap); 679 } 680 void CGdiplusExt::GdipDeleteGraphics(void* graphics) 681 { 682 CGdiplusExt& GdiplusExt = ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt; 683 CallFunc(GdipDeleteGraphics)((GpGraphics*)graphics); 684 } 685 FX_BOOL CGdiplusExt::StretchBitMask(HDC hDC, BOOL bMonoDevice, const CFX_DIBitmap* pBitmap, int dest_left, int dest_top, 686 int dest_width, int dest_height, FX_DWORD argb, const FX_RECT* pClipRect, int flags) 687 { 688 ASSERT(pBitmap->GetBPP() == 1); 689 CGdiplusExt& GdiplusExt = ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt; 690 GpGraphics* pGraphics = NULL; 691 CallFunc(GdipCreateFromHDC)(hDC, &pGraphics); 692 CallFunc(GdipSetPageUnit)(pGraphics, UnitPixel); 693 if (flags & FXDIB_NOSMOOTH) { 694 CallFunc(GdipSetInterpolationMode)(pGraphics, InterpolationModeNearestNeighbor); 695 } else { 696 CallFunc(GdipSetInterpolationMode)(pGraphics, InterpolationModeHighQuality); 697 } 698 OutputImageMask(pGraphics, bMonoDevice, pBitmap, dest_left, dest_top, dest_width, dest_height, argb, pClipRect); 699 CallFunc(GdipDeleteGraphics)(pGraphics); 700 return TRUE; 701 } 702 FX_BOOL CGdiplusExt::StretchDIBits(HDC hDC, const CFX_DIBitmap* pBitmap, int dest_left, int dest_top, 703 int dest_width, int dest_height, const FX_RECT* pClipRect, int flags) 704 { 705 GpGraphics* pGraphics; 706 CGdiplusExt& GdiplusExt = ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt; 707 CallFunc(GdipCreateFromHDC)(hDC, &pGraphics); 708 CallFunc(GdipSetPageUnit)(pGraphics, UnitPixel); 709 if (flags & FXDIB_NOSMOOTH) { 710 CallFunc(GdipSetInterpolationMode)(pGraphics, InterpolationModeNearestNeighbor); 711 } else if (pBitmap->GetWidth() > abs(dest_width) / 2 || pBitmap->GetHeight() > abs(dest_height) / 2) { 712 CallFunc(GdipSetInterpolationMode)(pGraphics, InterpolationModeHighQuality); 713 } else { 714 CallFunc(GdipSetInterpolationMode)(pGraphics, InterpolationModeBilinear); 715 } 716 FX_RECT src_rect(0, 0, pBitmap->GetWidth(), pBitmap->GetHeight()); 717 OutputImage(pGraphics, pBitmap, &src_rect, dest_left, dest_top, dest_width, dest_height); 718 CallFunc(GdipDeleteGraphics)(pGraphics); 719 CallFunc(GdipDeleteGraphics)(pGraphics); 720 return TRUE; 721 } 722 static GpPen* _GdipCreatePen(const CFX_GraphStateData* pGraphState, const CFX_AffineMatrix* pMatrix, DWORD argb, FX_BOOL bTextMode = FALSE) 723 { 724 CGdiplusExt& GdiplusExt = ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt; 725 FX_FLOAT width = pGraphState ? pGraphState->m_LineWidth : 1.0f; 726 if (!bTextMode) { 727 FX_FLOAT unit = pMatrix == NULL ? 1.0f : FXSYS_Div(1.0f, (pMatrix->GetXUnit() + pMatrix->GetYUnit()) / 2); 728 if (width < unit) { 729 width = unit; 730 } 731 } 732 GpPen* pPen = NULL; 733 CallFunc(GdipCreatePen1)((ARGB)argb, width, UnitWorld, &pPen); 734 LineCap lineCap; 735 DashCap dashCap = DashCapFlat; 736 FX_BOOL bDashExtend = FALSE; 737 switch(pGraphState->m_LineCap) { 738 case CFX_GraphStateData::LineCapButt: 739 lineCap = LineCapFlat; 740 break; 741 case CFX_GraphStateData::LineCapRound: 742 lineCap = LineCapRound; 743 dashCap = DashCapRound; 744 bDashExtend = TRUE; 745 break; 746 case CFX_GraphStateData::LineCapSquare: 747 lineCap = LineCapSquare; 748 bDashExtend = TRUE; 749 break; 750 } 751 CallFunc(GdipSetPenLineCap197819)(pPen, lineCap, lineCap, dashCap); 752 LineJoin lineJoin; 753 switch(pGraphState->m_LineJoin) { 754 case CFX_GraphStateData::LineJoinMiter: 755 lineJoin = LineJoinMiterClipped; 756 break; 757 case CFX_GraphStateData::LineJoinRound: 758 lineJoin = LineJoinRound; 759 break; 760 case CFX_GraphStateData::LineJoinBevel: 761 lineJoin = LineJoinBevel; 762 break; 763 } 764 CallFunc(GdipSetPenLineJoin)(pPen, lineJoin); 765 if(pGraphState->m_DashCount) { 766 FX_FLOAT* pDashArray = FX_Alloc(FX_FLOAT, pGraphState->m_DashCount + pGraphState->m_DashCount % 2); 767 if (!pDashArray) { 768 return NULL; 769 } 770 int nCount = 0; 771 FX_FLOAT on_leftover = 0, off_leftover = 0; 772 for (int i = 0; i < pGraphState->m_DashCount; i += 2) { 773 FX_FLOAT on_phase = pGraphState->m_DashArray[i]; 774 FX_FLOAT off_phase; 775 if (i == pGraphState->m_DashCount - 1) { 776 off_phase = on_phase; 777 } else { 778 off_phase = pGraphState->m_DashArray[i + 1]; 779 } 780 on_phase /= width; 781 off_phase /= width; 782 if (on_phase + off_phase <= 0.00002f) { 783 on_phase = 1.0f / 10; 784 off_phase = 1.0f / 10; 785 } 786 if (bDashExtend) { 787 if (off_phase < 1) { 788 off_phase = 0; 789 } else { 790 off_phase -= 1; 791 } 792 on_phase += 1; 793 } 794 if (on_phase == 0 || off_phase == 0) { 795 if (nCount == 0) { 796 on_leftover += on_phase; 797 off_leftover += off_phase; 798 } else { 799 pDashArray[nCount - 2] += on_phase; 800 pDashArray[nCount - 1] += off_phase; 801 } 802 } else { 803 pDashArray[nCount++] = on_phase + on_leftover; 804 on_leftover = 0; 805 pDashArray[nCount++] = off_phase + off_leftover; 806 off_leftover = 0; 807 } 808 } 809 CallFunc(GdipSetPenDashArray)(pPen, pDashArray, nCount); 810 FX_FLOAT phase = pGraphState->m_DashPhase; 811 if (bDashExtend) 812 if (phase < 0.5f) { 813 phase = 0; 814 } else { 815 phase -= 0.5f; 816 } 817 CallFunc(GdipSetPenDashOffset)(pPen, phase); 818 FX_Free(pDashArray); 819 pDashArray = NULL; 820 } 821 CallFunc(GdipSetPenMiterLimit)(pPen, pGraphState->m_MiterLimit); 822 return pPen; 823 } 824 static BOOL IsSmallTriangle(PointF* points, const CFX_AffineMatrix* pMatrix, int& v1, int& v2) 825 { 826 int pairs[] = {1, 2, 0, 2, 0, 1}; 827 for (int i = 0; i < 3; i ++) { 828 int pair1 = pairs[i * 2]; 829 int pair2 = pairs[i * 2 + 1]; 830 FX_FLOAT x1 = points[pair1].X, x2 = points[pair2].X; 831 FX_FLOAT y1 = points[pair1].Y, y2 = points[pair2].Y; 832 if (pMatrix) { 833 pMatrix->Transform(x1, y1); 834 pMatrix->Transform(x2, y2); 835 } 836 FX_FLOAT dx = x1 - x2; 837 FX_FLOAT dy = y1 - y2; 838 FX_FLOAT distance_square = FXSYS_Mul(dx, dx) + FXSYS_Mul(dy, dy); 839 if (distance_square < (1.0f * 2 + 1.0f / 4)) { 840 v1 = i; 841 v2 = pair1; 842 return TRUE; 843 } 844 } 845 return FALSE; 846 } 847 BOOL CGdiplusExt::DrawPath(HDC hDC, const CFX_PathData* pPathData, 848 const CFX_AffineMatrix* pObject2Device, 849 const CFX_GraphStateData* pGraphState, 850 FX_DWORD fill_argb, 851 FX_DWORD stroke_argb, 852 int fill_mode 853 ) 854 { 855 int nPoints = pPathData->GetPointCount(); 856 if (nPoints == 0) { 857 return TRUE; 858 } 859 FX_PATHPOINT* pPoints = pPathData->GetPoints(); 860 GpGraphics* pGraphics = NULL; 861 CGdiplusExt& GdiplusExt = ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt; 862 CallFunc(GdipCreateFromHDC)(hDC, &pGraphics); 863 CallFunc(GdipSetPageUnit)(pGraphics, UnitPixel); 864 CallFunc(GdipSetPixelOffsetMode)(pGraphics, PixelOffsetModeHalf); 865 GpMatrix* pMatrix = NULL; 866 if (pObject2Device) { 867 CallFunc(GdipCreateMatrix2)(pObject2Device->a, pObject2Device->b, pObject2Device->c, pObject2Device->d, pObject2Device->e, pObject2Device->f, &pMatrix); 868 CallFunc(GdipSetWorldTransform)(pGraphics, pMatrix); 869 } 870 PointF *points = FX_Alloc(PointF, nPoints); 871 if (!points) { 872 return FALSE; 873 } 874 BYTE * types = FX_Alloc(BYTE, nPoints); 875 if (!types) { 876 FX_Free(points); 877 return FALSE; 878 } 879 int nSubPathes = 0; 880 FX_BOOL bSubClose = FALSE; 881 int pos_subclose = 0; 882 FX_BOOL bSmooth = FALSE; 883 int startpoint = 0; 884 for(int i = 0; i < nPoints; i++) { 885 points[i].X = pPoints[i].m_PointX; 886 points[i].Y = pPoints[i].m_PointY; 887 FX_FLOAT x, y; 888 if (pObject2Device) { 889 pObject2Device->Transform(pPoints[i].m_PointX, pPoints[i].m_PointY, x, y); 890 } else { 891 x = pPoints[i].m_PointX; 892 y = pPoints[i].m_PointY; 893 } 894 if (x > 50000 * 1.0f) { 895 points[i].X = 50000 * 1.0f; 896 } 897 if (x < -50000 * 1.0f) { 898 points[i].X = -50000 * 1.0f; 899 } 900 if (y > 50000 * 1.0f) { 901 points[i].Y = 50000 * 1.0f; 902 } 903 if (y < -50000 * 1.0f) { 904 points[i].Y = -50000 * 1.0f; 905 } 906 int point_type = pPoints[i].m_Flag & FXPT_TYPE; 907 if(point_type == FXPT_MOVETO) { 908 types[i] = PathPointTypeStart; 909 nSubPathes ++; 910 bSubClose = FALSE; 911 startpoint = i; 912 } else if (point_type == FXPT_LINETO) { 913 types[i] = PathPointTypeLine; 914 if (pPoints[i - 1].m_Flag == FXPT_MOVETO && (i == nPoints - 1 || pPoints[i + 1].m_Flag == FXPT_MOVETO) && 915 points[i].Y == points[i - 1].Y && points[i].X == points[i - 1].X) { 916 points[i].X += 0.01f; 917 continue; 918 } 919 if (!bSmooth && points[i].X != points[i - 1].X && points[i].Y != points[i - 1].Y) { 920 bSmooth = TRUE; 921 } 922 } else if (point_type == FXPT_BEZIERTO) { 923 types[i] = PathPointTypeBezier; 924 bSmooth = TRUE; 925 } 926 if (pPoints[i].m_Flag & FXPT_CLOSEFIGURE) { 927 if (bSubClose) { 928 types[pos_subclose] &= ~PathPointTypeCloseSubpath; 929 } else { 930 bSubClose = TRUE; 931 } 932 pos_subclose = i; 933 types[i] |= PathPointTypeCloseSubpath; 934 if (!bSmooth && points[i].X != points[startpoint].X && points[i].Y != points[startpoint].Y) { 935 bSmooth = TRUE; 936 } 937 } 938 } 939 if (fill_mode & FXFILL_NOPATHSMOOTH) { 940 bSmooth = FALSE; 941 CallFunc(GdipSetSmoothingMode)(pGraphics, SmoothingModeNone); 942 } else if (!(fill_mode & FXFILL_FULLCOVER)) { 943 if (!bSmooth && (fill_mode & 3)) { 944 bSmooth = TRUE; 945 } 946 if (bSmooth || pGraphState && pGraphState->m_LineWidth > 2) { 947 CallFunc(GdipSetSmoothingMode)(pGraphics, SmoothingModeAntiAlias); 948 } 949 } 950 int new_fill_mode = fill_mode & 3; 951 if (nPoints == 4 && pGraphState == NULL) { 952 int v1, v2; 953 if (IsSmallTriangle(points, pObject2Device, v1, v2)) { 954 GpPen* pPen = NULL; 955 CallFunc(GdipCreatePen1)(fill_argb, 1.0f, UnitPixel, &pPen); 956 CallFunc(GdipDrawLineI)(pGraphics, pPen, FXSYS_round(points[v1].X), FXSYS_round(points[v1].Y), 957 FXSYS_round(points[v2].X), FXSYS_round(points[v2].Y)); 958 CallFunc(GdipDeletePen)(pPen); 959 return TRUE; 960 } 961 } 962 GpPath* pGpPath = NULL; 963 CallFunc(GdipCreatePath2)(points, types, nPoints, GdiFillType2Gdip(new_fill_mode), &pGpPath); 964 if (!pGpPath) { 965 if (pMatrix) { 966 CallFunc(GdipDeleteMatrix)(pMatrix); 967 } 968 FX_Free(points); 969 FX_Free(types); 970 CallFunc(GdipDeleteGraphics)(pGraphics); 971 return FALSE; 972 } 973 if (new_fill_mode) { 974 GpBrush* pBrush = _GdipCreateBrush(fill_argb); 975 CallFunc(GdipSetPathFillMode)(pGpPath, GdiFillType2Gdip(new_fill_mode)); 976 CallFunc(GdipFillPath)(pGraphics, pBrush, pGpPath); 977 CallFunc(GdipDeleteBrush)(pBrush); 978 } 979 if (pGraphState && stroke_argb) { 980 GpPen* pPen = _GdipCreatePen(pGraphState, pObject2Device, stroke_argb, fill_mode & FX_STROKE_TEXT_MODE); 981 if (nSubPathes == 1) { 982 CallFunc(GdipDrawPath)(pGraphics, pPen, pGpPath); 983 } else { 984 int iStart = 0; 985 for (int i = 0; i < nPoints; i ++) { 986 if (i == nPoints - 1 || types[i + 1] == PathPointTypeStart) { 987 GpPath* pSubPath; 988 CallFunc(GdipCreatePath2)(points + iStart, types + iStart, i - iStart + 1, GdiFillType2Gdip(new_fill_mode), &pSubPath); 989 iStart = i + 1; 990 CallFunc(GdipDrawPath)(pGraphics, pPen, pSubPath); 991 CallFunc(GdipDeletePath)(pSubPath); 992 } 993 } 994 } 995 CallFunc(GdipDeletePen)(pPen); 996 } 997 if (pMatrix) { 998 CallFunc(GdipDeleteMatrix)(pMatrix); 999 } 1000 FX_Free(points); 1001 FX_Free(types); 1002 CallFunc(GdipDeletePath)(pGpPath); 1003 CallFunc(GdipDeleteGraphics)(pGraphics); 1004 return TRUE; 1005 } 1006 class GpStream : public IStream, public CFX_Object 1007 { 1008 LONG m_RefCount; 1009 int m_ReadPos; 1010 CFX_ByteTextBuf m_InterStream; 1011 public: 1012 GpStream() 1013 { 1014 m_RefCount = 1; 1015 m_ReadPos = 0; 1016 } 1017 virtual HRESULT STDMETHODCALLTYPE 1018 QueryInterface(REFIID iid, void ** ppvObject) 1019 { 1020 if (iid == __uuidof(IUnknown) || iid == __uuidof(IStream) || 1021 iid == __uuidof(ISequentialStream)) { 1022 *ppvObject = static_cast<IStream*>(this); 1023 AddRef(); 1024 return S_OK; 1025 } else { 1026 return E_NOINTERFACE; 1027 } 1028 } 1029 virtual ULONG STDMETHODCALLTYPE AddRef(void) 1030 { 1031 return (ULONG)InterlockedIncrement(&m_RefCount); 1032 } 1033 virtual ULONG STDMETHODCALLTYPE Release(void) 1034 { 1035 ULONG res = (ULONG) InterlockedDecrement(&m_RefCount); 1036 if (res == 0) { 1037 delete this; 1038 } 1039 return res; 1040 } 1041 public: 1042 virtual HRESULT STDMETHODCALLTYPE Read(void* Output, ULONG cb, ULONG* pcbRead) 1043 { 1044 size_t bytes_left; 1045 size_t bytes_out; 1046 if (pcbRead != NULL) { 1047 *pcbRead = 0; 1048 } 1049 if (m_ReadPos == m_InterStream.GetLength()) { 1050 return HRESULT_FROM_WIN32(ERROR_END_OF_MEDIA); 1051 } 1052 bytes_left = m_InterStream.GetLength() - m_ReadPos; 1053 bytes_out = FX_MIN(cb, bytes_left); 1054 FXSYS_memcpy32(Output, m_InterStream.GetBuffer() + m_ReadPos, bytes_out); 1055 m_ReadPos += (FX_INT32)bytes_out; 1056 if (pcbRead != NULL) { 1057 *pcbRead = (ULONG)bytes_out; 1058 } 1059 return S_OK; 1060 } 1061 virtual HRESULT STDMETHODCALLTYPE Write(void const* Input, ULONG cb, ULONG* pcbWritten) 1062 { 1063 if (cb <= 0) { 1064 if (pcbWritten != NULL) { 1065 *pcbWritten = 0; 1066 } 1067 return S_OK; 1068 } 1069 m_InterStream.InsertBlock(m_InterStream.GetLength(), Input, cb); 1070 if (pcbWritten != NULL) { 1071 *pcbWritten = cb; 1072 } 1073 return S_OK; 1074 } 1075 public: 1076 virtual HRESULT STDMETHODCALLTYPE SetSize(ULARGE_INTEGER) 1077 { 1078 return E_NOTIMPL; 1079 } 1080 virtual HRESULT STDMETHODCALLTYPE CopyTo(IStream*, ULARGE_INTEGER, ULARGE_INTEGER*, ULARGE_INTEGER*) 1081 { 1082 return E_NOTIMPL; 1083 } 1084 virtual HRESULT STDMETHODCALLTYPE Commit(DWORD) 1085 { 1086 return E_NOTIMPL; 1087 } 1088 virtual HRESULT STDMETHODCALLTYPE Revert(void) 1089 { 1090 return E_NOTIMPL; 1091 } 1092 virtual HRESULT STDMETHODCALLTYPE LockRegion(ULARGE_INTEGER, ULARGE_INTEGER, DWORD) 1093 { 1094 return E_NOTIMPL; 1095 } 1096 virtual HRESULT STDMETHODCALLTYPE UnlockRegion(ULARGE_INTEGER, ULARGE_INTEGER, DWORD) 1097 { 1098 return E_NOTIMPL; 1099 } 1100 virtual HRESULT STDMETHODCALLTYPE Clone(IStream **) 1101 { 1102 return E_NOTIMPL; 1103 } 1104 virtual HRESULT STDMETHODCALLTYPE Seek(LARGE_INTEGER liDistanceToMove, DWORD dwOrigin, ULARGE_INTEGER* lpNewFilePointer) 1105 { 1106 long start = 0; 1107 long new_read_position; 1108 switch(dwOrigin) { 1109 case STREAM_SEEK_SET: 1110 start = 0; 1111 break; 1112 case STREAM_SEEK_CUR: 1113 start = m_ReadPos; 1114 break; 1115 case STREAM_SEEK_END: 1116 start = m_InterStream.GetLength(); 1117 break; 1118 default: 1119 return STG_E_INVALIDFUNCTION; 1120 break; 1121 } 1122 new_read_position = start + (long)liDistanceToMove.QuadPart; 1123 if (new_read_position < 0 || new_read_position > m_InterStream.GetLength()) { 1124 return STG_E_SEEKERROR; 1125 } 1126 m_ReadPos = new_read_position; 1127 if (lpNewFilePointer != NULL) { 1128 lpNewFilePointer->QuadPart = m_ReadPos; 1129 } 1130 return S_OK; 1131 } 1132 virtual HRESULT STDMETHODCALLTYPE Stat(STATSTG* pStatstg, DWORD grfStatFlag) 1133 { 1134 if (pStatstg == NULL) { 1135 return STG_E_INVALIDFUNCTION; 1136 } 1137 ZeroMemory(pStatstg, sizeof(STATSTG)); 1138 pStatstg->cbSize.QuadPart = m_InterStream.GetLength(); 1139 return S_OK; 1140 } 1141 }; 1142 typedef struct { 1143 BITMAPINFO* pbmi; 1144 int Stride; 1145 LPBYTE pScan0; 1146 GpBitmap* pBitmap; 1147 BitmapData* pBitmapData; 1148 GpStream* pStream; 1149 } PREVIEW3_DIBITMAP; 1150 static PREVIEW3_DIBITMAP* LoadDIBitmap(WINDIB_Open_Args_ args) 1151 { 1152 GpBitmap* pBitmap; 1153 GpStream* pStream = NULL; 1154 CGdiplusExt& GdiplusExt = ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt; 1155 Status status = Ok; 1156 if (args.flags == WINDIB_OPEN_PATHNAME) { 1157 status = CallFunc(GdipCreateBitmapFromFileICM)((wchar_t*)args.path_name, &pBitmap); 1158 } else { 1159 if (args.memory_size == 0 || !args.memory_base) { 1160 return NULL; 1161 } 1162 pStream = FX_NEW GpStream; 1163 if (!pStream) { 1164 return NULL; 1165 } 1166 pStream->Write(args.memory_base, (ULONG)args.memory_size, NULL); 1167 status = CallFunc(GdipCreateBitmapFromStreamICM)(pStream, &pBitmap); 1168 } 1169 if (status != Ok) { 1170 if (pStream) { 1171 pStream->Release(); 1172 } 1173 return NULL; 1174 } 1175 UINT height, width; 1176 CallFunc(GdipGetImageHeight)(pBitmap, &height); 1177 CallFunc(GdipGetImageWidth)(pBitmap, &width); 1178 PixelFormat pixel_format; 1179 CallFunc(GdipGetImagePixelFormat)(pBitmap, &pixel_format); 1180 int info_size = sizeof(BITMAPINFOHEADER); 1181 int bpp = 24; 1182 int dest_pixel_format = PixelFormat24bppRGB; 1183 if (pixel_format == PixelFormat1bppIndexed) { 1184 info_size += 8; 1185 bpp = 1; 1186 dest_pixel_format = PixelFormat1bppIndexed; 1187 } else if (pixel_format == PixelFormat8bppIndexed) { 1188 info_size += 1024; 1189 bpp = 8; 1190 dest_pixel_format = PixelFormat8bppIndexed; 1191 } else if (pixel_format == PixelFormat32bppARGB) { 1192 bpp = 32; 1193 dest_pixel_format = PixelFormat32bppARGB; 1194 } 1195 LPBYTE buf = FX_Alloc(BYTE, info_size); 1196 if (!buf) { 1197 if (pStream) { 1198 pStream->Release(); 1199 } 1200 return NULL; 1201 } 1202 BITMAPINFOHEADER* pbmih = (BITMAPINFOHEADER*)buf; 1203 FXSYS_memset32(buf, 0, info_size); 1204 pbmih->biBitCount = bpp; 1205 pbmih->biCompression = BI_RGB; 1206 pbmih->biHeight = -(int)height; 1207 pbmih->biPlanes = 1; 1208 pbmih->biWidth = width; 1209 Rect rect(0, 0, width, height); 1210 BitmapData* pBitmapData = FX_Alloc(BitmapData, 1); 1211 if (!pBitmapData) { 1212 if (pStream) { 1213 pStream->Release(); 1214 } 1215 return NULL; 1216 } 1217 CallFunc(GdipBitmapLockBits)(pBitmap, &rect, ImageLockModeRead, 1218 dest_pixel_format, pBitmapData); 1219 if (pixel_format == PixelFormat1bppIndexed || pixel_format == PixelFormat8bppIndexed) { 1220 DWORD* ppal = (DWORD*)(buf + sizeof(BITMAPINFOHEADER)); 1221 struct { 1222 UINT flags; 1223 UINT Count; 1224 DWORD Entries[256]; 1225 } pal; 1226 int size = 0; 1227 CallFunc(GdipGetImagePaletteSize)(pBitmap, &size); 1228 CallFunc(GdipGetImagePalette)(pBitmap, (ColorPalette*)&pal, size); 1229 int entries = pixel_format == PixelFormat1bppIndexed ? 2 : 256; 1230 for (int i = 0; i < entries; i ++) { 1231 ppal[i] = pal.Entries[i] & 0x00ffffff; 1232 } 1233 } 1234 PREVIEW3_DIBITMAP* pInfo = FX_Alloc(PREVIEW3_DIBITMAP, 1); 1235 if (!pInfo) { 1236 if (pStream) { 1237 pStream->Release(); 1238 } 1239 return NULL; 1240 } 1241 pInfo->pbmi = (BITMAPINFO*)buf; 1242 pInfo->pScan0 = (LPBYTE)pBitmapData->Scan0; 1243 pInfo->Stride = pBitmapData->Stride; 1244 pInfo->pBitmap = pBitmap; 1245 pInfo->pBitmapData = pBitmapData; 1246 pInfo->pStream = pStream; 1247 return pInfo; 1248 } 1249 static void FreeDIBitmap(PREVIEW3_DIBITMAP* pInfo) 1250 { 1251 CGdiplusExt& GdiplusExt = ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt; 1252 CallFunc(GdipBitmapUnlockBits)(pInfo->pBitmap, pInfo->pBitmapData); 1253 CallFunc(GdipDisposeImage)(pInfo->pBitmap); 1254 FX_Free(pInfo->pBitmapData); 1255 FX_Free((LPBYTE)pInfo->pbmi); 1256 if (pInfo->pStream) { 1257 pInfo->pStream->Release(); 1258 } 1259 FX_Free(pInfo); 1260 } 1261 CFX_DIBitmap* _FX_WindowsDIB_LoadFromBuf(BITMAPINFO* pbmi, LPVOID pData, FX_BOOL bAlpha); 1262 CFX_DIBitmap* CGdiplusExt::LoadDIBitmap(WINDIB_Open_Args_ args) 1263 { 1264 PREVIEW3_DIBITMAP* pInfo = ::LoadDIBitmap(args); 1265 if (pInfo == NULL) { 1266 return NULL; 1267 } 1268 int height = abs(pInfo->pbmi->bmiHeader.biHeight); 1269 int width = pInfo->pbmi->bmiHeader.biWidth; 1270 int dest_pitch = (width * pInfo->pbmi->bmiHeader.biBitCount + 31) / 32 * 4; 1271 LPBYTE pData = FX_Alloc(BYTE, dest_pitch * height); 1272 if (pData == NULL) { 1273 FreeDIBitmap(pInfo); 1274 return NULL; 1275 } 1276 if (dest_pitch == pInfo->Stride) { 1277 FXSYS_memcpy32(pData, pInfo->pScan0, dest_pitch * height); 1278 } else for (int i = 0; i < height; i ++) { 1279 FXSYS_memcpy32(pData + dest_pitch * i, pInfo->pScan0 + pInfo->Stride * i, dest_pitch); 1280 } 1281 CFX_DIBitmap* pDIBitmap = _FX_WindowsDIB_LoadFromBuf(pInfo->pbmi, pData, pInfo->pbmi->bmiHeader.biBitCount == 32); 1282 FX_Free(pData); 1283 FreeDIBitmap(pInfo); 1284 return pDIBitmap; 1285 } 1286 #endif 1287