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