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